Help understanding rp_filter as applied via sysctl.conf

I’ve added the following to /etc/sysctl.conf and I’ve manually set wg0 to ‘loose’ via Luci.

net.ipv4.conf.all.rp_filter = 1
net.ipv4.conf.default.rp_filter = 1
net.ipv4.conf.all.log_martians = 1

After a reboot I see:

# sysctl -A | grep "\.rp_filter"
net.ipv4.conf.all.rp_filter = 1
net.ipv4.conf.br-lan.rp_filter = 1
net.ipv4.conf.br-lan/10.rp_filter = 1
net.ipv4.conf.br-lan/11.rp_filter = 1
net.ipv4.conf.default.rp_filter = 1
net.ipv4.conf.eth0.rp_filter = 0
net.ipv4.conf.eth1.rp_filter = 1
net.ipv4.conf.ifb4eth0.rp_filter = 1
net.ipv4.conf.lo.rp_filter = 1
net.ipv4.conf.wg0.rp_filter = 2

What is the reason that eth0 hasn’t had the setting applied? I can set it manually and everything works fine (limited testing) but I’m unsure if I should or if I need to. I tried disabling SQM (ifb4eth0), rebooted and the result was the same.

Router is a Raspberry Pi CM4 with DFRobot router board. eth0 is onboard Broadcom.

Is Eth0 attached to br-lan? If yes then rpfilter set on br-lan is "active".
In general, rpfilter is needed with asynchronous routing. And mainly only relevant in the so called "default free zone", where you have explicit routes to every network but no default route. Like if you use bgp with a large tier and not "only" with an ISP which usually provides a default route too if you ask...
See
https://en.m.wikipedia.org/wiki/Reverse-path_forwarding and
https://datatracker.ietf.org/doc/html/rfc3704

No. eth0 is WAN and br-lan (eth1) is LAN.

ifb4eth0 is WAN with Cake traffic shaping and is set to 1 so I think I’m covered? However, if I disable SQM then I’m not.

I just applied the same settings to a Belkin RT3200 (mt7622) operating as a dumb-ap. Here are the results:

net.ipv4.conf.all.rp_filter = 1
net.ipv4.conf.br-lan.rp_filter = 1
net.ipv4.conf.br-lan/10.rp_filter = 1
net.ipv4.conf.br-lan/11.rp_filter = 1
net.ipv4.conf.default.rp_filter = 1
net.ipv4.conf.eth0.rp_filter = 1
net.ipv4.conf.lan1.rp_filter = 0
net.ipv4.conf.lan2.rp_filter = 1
net.ipv4.conf.lan3.rp_filter = 1
net.ipv4.conf.lan4.rp_filter = 1
net.ipv4.conf.lo.rp_filter = 1
net.ipv4.conf.wan.rp_filter = 1
net.ipv4.conf.wl1-ap0.rp_filter = 1
net.ipv4.conf.wl1-ap1.rp_filter = 1
net.ipv4.conf.wlan0.rp_filter = 1

This time we see ‘lan1.rp_filter = 0’

For comparison I applied the same settings to a Raspberry Pi 4 running Raspberry OS. Here are the results:

net.ipv4.conf.all.rp_filter = 1
net.ipv4.conf.default.rp_filter = 1
net.ipv4.conf.eth0.rp_filter = 2
net.ipv4.conf.lo.rp_filter = 0

Now we see ‘net.ipv4.conf.lo.rp_filter = 0’ and ‘net.ipv4.conf.eth0.rp_filter = 2’

I can’t tell if I’m looking at a bug or a feature?

Edit:
And lastly an Intel Thinkpad running Ubuntu 22.04

net.ipv4.conf.all.rp_filter = 1
net.ipv4.conf.default.rp_filter = 1
net.ipv4.conf.enp0s31f6.rp_filter = 2
net.ipv4.conf.lo.rp_filter = 2
net.ipv4.conf.wlp0s20f3.rp_filter = 2

Ok lets start from the beginning...

What is your goal / what do you want to achieve?
Do you have an actually issue you want to solve, or is it just part of your educational journey?

Did you have looked at the linked wikipedia page and RFC?

rp_filter or reverse path forwarding does the following:

(For a moment, just forget that there is a firewall in place/active...)

Scenario 1: You have a router with 3 interfaces, and each interface has a network.

eth0: 192.0.2.0/24
eth1: 198.51.100.0/24
eth2: 203.0.113.0/24

If you have no rp_filter set, then linux does not care about the source/incomming interface of an IP packet.
If you have set strict (1), then an packet with the source 203.0.113.0/24, which comes in though eth0 or eth1, (but not from eth2) would be ignored.
If you have set loose (2) then it would be "accepted" (passes) because you have at least a route / assigned this network on a local interface...

Scenario 2: Like scenario 1, but now you have a default route on eth0, too.
The same rules as in scenario applies here, too. BUT:
If eth0 is your uplink aka has a default route and you have set loose mode on any interface, then the packet is processed anyway.
Only if you have set strict mode on eth1 and eth2 then packets coming in on eth0 but with a source 198.51.100.0/24 or 203.0.113.0/24 or would be droped.

Again, in a home environment setting RPF mostly makes no sense at all, because no ISP would allow any packets from RFC1918 coming in on your WAN connection anyway. So it would only make sense if you have some funky routing in place in your network. But asynchronous routing is not bad per default...
RPF is intended and invented for the default free zone: https://en.wikipedia.org/wiki/Default-free_zone

1 Like

Thank you for the info about rp_filter. Your explanation makes perfect sense. I’m not ignoring the fact that it’s likely not needed for home use. I understand your curiosity as to why I want to set this but that’s a different discussion.

As for the problem I’m trying to solve, I think I solved it by manually setting the interfaces not changed by the sysctl.conf edits. The question is, should I? Is there a valid reason it doesn’t change at boot time?

The kernel docs regarding rp_filter mention “Note that some ditstributions enable it in startup scripts.” Debian nor OpenWrt set it but Ubuntu does set it to ‘loose’ (2) via /etc/sysctl.d/10-network-security.conf. If we exclude the Ubuntu results I posted above it seems to be random, like a bug.

This is not an OpenWrt specific issue or question, though it is networking adjacent. I should have tested this on other machines and distros prior to posting and maybe asked this question elsewhere. If this question is outside the scope of OpenWrt then I apologize for the noise.

You need to apply rp_filter via netifd, like checkboxes in interface list or /etc/config/network.

That's what I did for eth0.

The thing is not all network ports are named same, as I understood you did it to WAN device so that it does not respond to lan arp requests?

No. Everything works fine with it applied. My question was why it’s not set on eth0 when I added the following to sysctl.conf followed by a reboot.

net.ipv4.conf.all.rp_filter = 1
net.ipv4.conf.default.rp_filter = 1

I wasn’t sure if this was intentional or perhaps a bug upstream.

You need to do in reverse order btw...

1 Like

I didn't know that, thank you. However, I still get the same result with them reversed

The rp_filter netifd parameter is weird in regard that its absence means not to change sysctl value, to get deterministic value you need to have the parameter.

1 Like

Fair enough. Thank you again!