* [PATCH net v2 0/4] ipv4: restrict on-link fallback to lookup misses
@ 2026-11-10 6:15 liamsmith827
2026-11-10 6:15 ` [PATCH net v2 1/4] ipv4: add FIB_LOOKUP_REPORT_MISS liamsmith827
` (3 more replies)
0 siblings, 4 replies; 5+ messages in thread
From: liamsmith827 @ 2026-11-10 6:15 UTC (permalink / raw)
To: netdev
Cc: David Ahern, Ido Schimmel, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Simon Horman, Shuah Khan,
linux-kselftest, linux-kernel, liamsmith827
From: liamsmith827 <liamsmith827@proton.me>
For non-vrf unicast, the on-link fallback currently occurs regardless of
the particular error returned by fib_lookup(). As a result, routes and
rules that are supposed to restrict traffic (blackhole, prohibit,
unreachable) are unable to do so comprehensively.
A specific example of this being a problem is within Android, where the
VPN "kill switch" is implemented with prohibit rules. Any process that
can set flowi4_oif (SO_BINDTODEVICE, IP_UNICAST_IF, IP_PKTINFO, etc.) is
able to utilize this fallback, meaning unprivileged Android apps can
trivially bypass the VPN. This is particularly bad on cellular networks,
where ARP is often not needed.
The first patch adds FIB_LOOKUP_REPORT_MISS. IPv4 FIB lookup maps a
routing miss to -ENETUNREACH, which is also returned when an unreachable
rule is encountered. This flag prevents the mapping, returning -ESRCH
instead.
The second patch uses this flag to restrict the fallback to routing
lookup misses for non-vrf unicast. The fallback is still always taken
for multicast, regardless of any restrictions or misses.
The third patch updates tests now that the on-link fallback has been
restricted to routing lookup misses for non-vrf unicast.
The fourth patch replaces an existing comment which describes obsolete
fib_lookup(), MSG_DONTROUTE and IPv6 behavior.
This was originally observed on an Android device, by way of packet
capture.
Tested fcnal-test.sh in UML with CONFIG_IP_MULTIPLE_TABLES both enabled
and disabled.
v2:
- Restrict the fallback to routing lookup misses, instead of only
honoring prohibit (-EACCES).
- Add FIB_LOOKUP_REPORT_MISS to differentiate a routing miss from an
unreachable rule.
- Split the comment update out into its own patch and remove the
signature.
- Enable all of the commented out device bind tests in
ipv4_ping_novrf(), add a route miss test and update the UDP test
expectations.
- Target net instead of net-next, add Fixes and Cc stable.
- Drop RFC.
v1: https://lore.kernel.org/netdev/20261019032406.88874-1-liamsmith827@grapheneos.org/
liamsmith827 (4):
ipv4: add FIB_LOOKUP_REPORT_MISS
ipv4: restrict on-link fallback to lookup misses
selftests: net: test restricted on-link fallback
ipv4: replace obsolete routing comment
include/net/fib_rules.h | 5 +++
include/net/ip_fib.h | 6 +--
net/ipv4/fib_rules.c | 2 +-
net/ipv4/route.c | 34 ++++++++--------
tools/testing/selftests/net/fcnal-test.sh | 47 +++++++++++++----------
5 files changed, 51 insertions(+), 43 deletions(-)
--
2.47.3
^ permalink raw reply [flat|nested] 5+ messages in thread
* [PATCH net v2 1/4] ipv4: add FIB_LOOKUP_REPORT_MISS
2026-11-10 6:15 [PATCH net v2 0/4] ipv4: restrict on-link fallback to lookup misses liamsmith827
@ 2026-11-10 6:15 ` liamsmith827
2026-11-10 6:15 ` [PATCH net v2 2/4] ipv4: restrict on-link fallback to lookup misses liamsmith827
` (2 subsequent siblings)
3 siblings, 0 replies; 5+ messages in thread
From: liamsmith827 @ 2026-11-10 6:15 UTC (permalink / raw)
To: netdev
Cc: David Ahern, Ido Schimmel, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Simon Horman, Shuah Khan,
linux-kselftest, linux-kernel, liamsmith827, stable
From: liamsmith827 <liamsmith827@proton.me>
IPv4 FIB lookup maps a routing miss to -ENETUNREACH, which is also
returned when an unreachable rule is encountered. This flag prevents the
mapping, returning -ESRCH instead.
Cc: stable@vger.kernel.org
Signed-off-by: liamsmith827 <liamsmith827@proton.me>
---
include/net/fib_rules.h | 5 +++++
include/net/ip_fib.h | 6 +++---
net/ipv4/fib_rules.c | 2 +-
3 files changed, 9 insertions(+), 4 deletions(-)
diff --git a/include/net/fib_rules.h b/include/net/fib_rules.h
index c6b94790fa81..bcb6809dbd10 100644
--- a/include/net/fib_rules.h
+++ b/include/net/fib_rules.h
@@ -59,6 +59,11 @@ struct fib_lookup_arg {
int flags;
#define FIB_LOOKUP_NOREF 1
#define FIB_LOOKUP_IGNORE_LINKSTATE 2
+/* Return -ESRCH instead of mapping it to -ENETUNREACH. Only applies to IPv4
+ * lookups. When used with FIB_LOOKUP_NOREF, -ESRCH indicates the lookup
+ * exhausted all rules and tables without finding a usable route.
+ */
+#define FIB_LOOKUP_REPORT_MISS 4
};
struct fib_rules_ops {
diff --git a/include/net/ip_fib.h b/include/net/ip_fib.h
index 92f4eb8b86d7..d0b4f261585a 100644
--- a/include/net/ip_fib.h
+++ b/include/net/ip_fib.h
@@ -318,7 +318,7 @@ static inline int fib_lookup(struct net *net, const struct flowi4 *flp,
struct fib_result *res, unsigned int flags)
{
struct fib_table *tb;
- int err = -ENETUNREACH;
+ int err = -EAGAIN;
rcu_read_lock();
@@ -327,7 +327,7 @@ static inline int fib_lookup(struct net *net, const struct flowi4 *flp,
err = fib_table_lookup(tb, flp, res, flags | FIB_LOOKUP_NOREF);
if (err == -EAGAIN)
- err = -ENETUNREACH;
+ err = (flags & FIB_LOOKUP_REPORT_MISS) ? -ESRCH : -ENETUNREACH;
rcu_read_unlock();
@@ -398,7 +398,7 @@ static inline int fib_lookup(struct net *net, struct flowi4 *flp,
err = fib_table_lookup(tb, flp, res, flags);
if (err == -EAGAIN)
- err = -ENETUNREACH;
+ err = (flags & FIB_LOOKUP_REPORT_MISS) ? -ESRCH : -ENETUNREACH;
out:
rcu_read_unlock();
diff --git a/net/ipv4/fib_rules.c b/net/ipv4/fib_rules.c
index 060501b376a8..3d7dcb8d0865 100644
--- a/net/ipv4/fib_rules.c
+++ b/net/ipv4/fib_rules.c
@@ -101,7 +101,7 @@ int __fib_lookup(struct net *net, struct flowi4 *flp,
res->tclassid = 0;
#endif
- if (err == -ESRCH)
+ if (err == -ESRCH && !(flags & FIB_LOOKUP_REPORT_MISS))
err = -ENETUNREACH;
return err;
--
2.47.3
^ permalink raw reply [flat|nested] 5+ messages in thread
* [PATCH net v2 2/4] ipv4: restrict on-link fallback to lookup misses
2026-11-10 6:15 [PATCH net v2 0/4] ipv4: restrict on-link fallback to lookup misses liamsmith827
2026-11-10 6:15 ` [PATCH net v2 1/4] ipv4: add FIB_LOOKUP_REPORT_MISS liamsmith827
@ 2026-11-10 6:15 ` liamsmith827
2026-11-10 6:15 ` [PATCH net v2 3/4] selftests: net: test restricted on-link fallback liamsmith827
2026-11-10 6:15 ` [PATCH net v2 4/4] ipv4: replace obsolete routing comment liamsmith827
3 siblings, 0 replies; 5+ messages in thread
From: liamsmith827 @ 2026-11-10 6:15 UTC (permalink / raw)
To: netdev
Cc: David Ahern, Ido Schimmel, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Simon Horman, Shuah Khan,
linux-kselftest, linux-kernel, liamsmith827, stable
From: liamsmith827 <liamsmith827@proton.me>
For non-vrf unicast, the on-link fallback currently occurs regardless of
the particular error returned by fib_lookup(). As a result, routes and
rules that are supposed to restrict traffic (blackhole, prohibit,
unreachable) are unable to do so comprehensively.
A specific example of this being a problem is within Android, where the
VPN "kill switch" is implemented with prohibit rules. Any process that
can set flowi4_oif (SO_BINDTODEVICE, IP_UNICAST_IF, IP_PKTINFO, etc.) is
able to utilize this fallback, meaning unprivileged Android apps can
trivially bypass the VPN. This is particularly bad on cellular networks,
where ARP is often not needed.
Restrict the fallback to routing lookup misses.
This was originally observed on an Android device, by way of packet
capture.
Tested fcnal-test.sh in UML with CONFIG_IP_MULTIPLE_TABLES both enabled
and disabled.
Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
Cc: stable@vger.kernel.org
Signed-off-by: liamsmith827 <liamsmith827@proton.me>
---
net/ipv4/route.c | 7 +++++--
1 file changed, 5 insertions(+), 2 deletions(-)
diff --git a/net/ipv4/route.c b/net/ipv4/route.c
index 3a90c8d28b94..80a2c8a3c571 100644
--- a/net/ipv4/route.c
+++ b/net/ipv4/route.c
@@ -2851,12 +2851,13 @@ struct rtable *ip_route_output_key_hash_rcu(struct net *net, struct flowi4 *fl4,
goto make_route;
}
- err = fib_lookup(net, fl4, res, 0);
+ err = fib_lookup(net, fl4, res, FIB_LOOKUP_REPORT_MISS);
if (err) {
res->fi = NULL;
res->table = NULL;
if (fl4->flowi4_oif &&
- (ipv4_is_multicast(fl4->daddr) || !fl4->flowi4_l3mdev)) {
+ (ipv4_is_multicast(fl4->daddr) ||
+ (!fl4->flowi4_l3mdev && err == -ESRCH))) {
/* Apparently, routing tables are wrong. Assume,
* that the destination is on link.
*
@@ -2881,6 +2882,8 @@ struct rtable *ip_route_output_key_hash_rcu(struct net *net, struct flowi4 *fl4,
res->type = RTN_UNICAST;
goto make_route;
}
+ /* Reverse the mapping induced by FIB_LOOKUP_REPORT_MISS. */
+ err = err == -ESRCH ? -ENETUNREACH : err;
rth = ERR_PTR(err);
goto out;
}
--
2.47.3
^ permalink raw reply [flat|nested] 5+ messages in thread
* [PATCH net v2 3/4] selftests: net: test restricted on-link fallback
2026-11-10 6:15 [PATCH net v2 0/4] ipv4: restrict on-link fallback to lookup misses liamsmith827
2026-11-10 6:15 ` [PATCH net v2 1/4] ipv4: add FIB_LOOKUP_REPORT_MISS liamsmith827
2026-11-10 6:15 ` [PATCH net v2 2/4] ipv4: restrict on-link fallback to lookup misses liamsmith827
@ 2026-11-10 6:15 ` liamsmith827
2026-11-10 6:15 ` [PATCH net v2 4/4] ipv4: replace obsolete routing comment liamsmith827
3 siblings, 0 replies; 5+ messages in thread
From: liamsmith827 @ 2026-11-10 6:15 UTC (permalink / raw)
To: netdev
Cc: David Ahern, Ido Schimmel, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Simon Horman, Shuah Khan,
linux-kselftest, linux-kernel, liamsmith827, stable
From: liamsmith827 <liamsmith827@proton.me>
Update tests now that the on-link fallback has been restricted to
routing lookup misses for non-vrf unicast.
Cc: stable@vger.kernel.org
Signed-off-by: liamsmith827 <liamsmith827@proton.me>
---
tools/testing/selftests/net/fcnal-test.sh | 47 +++++++++++++----------
1 file changed, 26 insertions(+), 21 deletions(-)
diff --git a/tools/testing/selftests/net/fcnal-test.sh b/tools/testing/selftests/net/fcnal-test.sh
index a50609535fed..c048d5be139d 100755
--- a/tools/testing/selftests/net/fcnal-test.sh
+++ b/tools/testing/selftests/net/fcnal-test.sh
@@ -619,17 +619,29 @@ ipv4_ping_novrf()
run_cmd ping -c1 -w1 -I ${NSA_DEV} ${a}
log_test_addr ${a} $? 0 "ping local, device bind"
- # loopback addresses not reachable from device bind
- # fails in a really weird way though because ipv4 special cases
- # route lookups with oif set.
+ # loopback addresses not reachable from device bind, unreachable default route
for a in ${NSA_LO_IP} 127.0.0.1
do
log_start
show_hint "Fails since address on loopback device is out of device scope"
run_cmd ping -c1 -w1 -I ${NSA_DEV} ${a}
- log_test_addr ${a} $? 1 "ping local, device bind"
+ log_test_addr ${a} $? 2 "ping local, device bind, unreachable default route"
done
+ # loopback addresses not reachable from device bind, route miss
+ log_start
+ setup_cmd ip route del unreachable default metric 8192
+
+ for a in ${NSA_LO_IP} 127.0.0.1
+ do
+ log_start
+ show_hint "Fails since address on loopback device is out of device scope"
+ run_cmd ping -c1 -w1 -I ${NSA_DEV} ${a}
+ log_test_addr ${a} $? 1 "ping local, device bind, route miss"
+ done
+
+ setup_cmd ip route add unreachable default metric 8192
+
#
# ip rule blocks reachability to remote address
#
@@ -643,10 +655,9 @@ ipv4_ping_novrf()
run_cmd ping -c1 -w1 ${a}
log_test_addr ${a} $? 2 "ping out, blocked by rule"
- # NOTE: ipv4 actually allows the lookup to fail and yet still create
- # a viable rtable if the oif (e.g., bind to device) is set, so this
- # case succeeds despite the rule
- # run_cmd ping -c1 -w1 -I ${NSA_DEV} ${a}
+ log_start
+ run_cmd ping -c1 -w1 -I ${NSA_DEV} ${a}
+ log_test_addr ${a} $? 2 "ping out, device bind, blocked by rule"
a=${NSA_LO_IP}
log_start
@@ -671,10 +682,9 @@ ipv4_ping_novrf()
run_cmd ping -c1 -w1 ${a}
log_test_addr ${a} $? 2 "ping out, blocked by route"
- # NOTE: ipv4 actually allows the lookup to fail and yet still create
- # a viable rtable if the oif (e.g., bind to device) is set, so this
- # case succeeds despite not having a route for the address
- # run_cmd ping -c1 -w1 -I ${NSA_DEV} ${a}
+ log_start
+ run_cmd ping -c1 -w1 -I ${NSA_DEV} ${a}
+ log_test_addr ${a} $? 2 "ping out, device bind, blocked by route"
a=${NSA_LO_IP}
log_start
@@ -692,10 +702,9 @@ ipv4_ping_novrf()
run_cmd ping -c1 -w1 ${a}
log_test_addr ${a} $? 2 "ping out, unreachable default route"
- # NOTE: ipv4 actually allows the lookup to fail and yet still create
- # a viable rtable if the oif (e.g., bind to device) is set, so this
- # case succeeds despite not having a route for the address
- # run_cmd ping -c1 -w1 -I ${NSA_DEV} ${a}
+ log_start
+ run_cmd ping -c1 -w1 -I ${NSA_DEV} ${a}
+ log_test_addr ${a} $? 2 "ping out, device bind, unreachable default route"
}
ipv4_ping_vrf()
@@ -1602,10 +1611,6 @@ ipv4_udp_novrf()
run_cmd nettest -D -d ${NSA_DEV} -S -r ${a} -U
log_test_addr ${a} $? 0 "Global server, device client via IP_UNICAST_IF, local connection, with connect()"
-
- # IPv4 with device bind has really weird behavior - it overrides the
- # fib lookup, generates an rtable and tries to send the packet. This
- # causes failures for local traffic at different places
for a in ${NSA_LO_IP} 127.0.0.1
do
log_start
@@ -1613,7 +1618,7 @@ ipv4_udp_novrf()
run_cmd nettest -D -s &
wait_local_port_listen ${NSA} 12345 udp
run_cmd nettest -D -r ${a} -d ${NSA_DEV}
- log_test_addr ${a} $? 2 "Global server, device client, local connection"
+ log_test_addr ${a} $? 1 "Global server, device client, local connection"
log_start
show_hint "Should fail since addresses on loopback are out of device scope"
--
2.47.3
^ permalink raw reply [flat|nested] 5+ messages in thread
* [PATCH net v2 4/4] ipv4: replace obsolete routing comment
2026-11-10 6:15 [PATCH net v2 0/4] ipv4: restrict on-link fallback to lookup misses liamsmith827
` (2 preceding siblings ...)
2026-11-10 6:15 ` [PATCH net v2 3/4] selftests: net: test restricted on-link fallback liamsmith827
@ 2026-11-10 6:15 ` liamsmith827
3 siblings, 0 replies; 5+ messages in thread
From: liamsmith827 @ 2026-11-10 6:15 UTC (permalink / raw)
To: netdev
Cc: David Ahern, Ido Schimmel, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Simon Horman, Shuah Khan,
linux-kselftest, linux-kernel, liamsmith827
From: liamsmith827 <liamsmith827@proton.me>
Replace an existing comment which describes obsolete fib_lookup(),
MSG_DONTROUTE and IPv6 behavior.
Signed-off-by: liamsmith827 <liamsmith827@proton.me>
---
net/ipv4/route.c | 27 +++++++++++----------------
1 file changed, 11 insertions(+), 16 deletions(-)
diff --git a/net/ipv4/route.c b/net/ipv4/route.c
index 80a2c8a3c571..ac94d8262b6e 100644
--- a/net/ipv4/route.c
+++ b/net/ipv4/route.c
@@ -2858,24 +2858,19 @@ struct rtable *ip_route_output_key_hash_rcu(struct net *net, struct flowi4 *fl4,
if (fl4->flowi4_oif &&
(ipv4_is_multicast(fl4->daddr) ||
(!fl4->flowi4_l3mdev && err == -ESRCH))) {
- /* Apparently, routing tables are wrong. Assume,
- * that the destination is on link.
+ /* When oif is specified, fib_lookup() is called
+ * primarily to determine if the destination is
+ * accessible directly or through a gateway. It also
+ * checks whether there are any traffic restrictions
+ * (blackhole, prohibit, unreachable), or if there's a
+ * routing lookup miss.
*
- * WHY? DW.
- * Because we are allowed to send to iface
- * even if it has NO routes and NO assigned
- * addresses. When oif is specified, routing
- * tables are looked up with only one purpose:
- * to catch if destination is gatewayed, rather than
- * direct. Moreover, if MSG_DONTROUTE is set,
- * we send packet, ignoring both routing tables
- * and ifaddr state. --ANK
- *
- *
- * We could make it even if oif is unknown,
- * likely IPv6, but we do not.
+ * This fallback path is always taken for multicast,
+ * regardless of any restrictions or misses. Non-vrf
+ * unicast does honor restrictions, but falls back if
+ * there's a miss. The destination is assumed on-link
+ * for both.
*/
-
if (fl4->saddr == 0)
fl4->saddr = inet_select_addr(dev_out, 0,
RT_SCOPE_LINK);
--
2.47.3
^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2026-11-10 6:16 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-11-10 6:15 [PATCH net v2 0/4] ipv4: restrict on-link fallback to lookup misses liamsmith827
2026-11-10 6:15 ` [PATCH net v2 1/4] ipv4: add FIB_LOOKUP_REPORT_MISS liamsmith827
2026-11-10 6:15 ` [PATCH net v2 2/4] ipv4: restrict on-link fallback to lookup misses liamsmith827
2026-11-10 6:15 ` [PATCH net v2 3/4] selftests: net: test restricted on-link fallback liamsmith827
2026-11-10 6:15 ` [PATCH net v2 4/4] ipv4: replace obsolete routing comment liamsmith827
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®