Bug 249261 - Kernel ignores RTAX_IFP if an exact RTAX_IFA match is found
Summary: Kernel ignores RTAX_IFP if an exact RTAX_IFA match is found
Status: New
Alias: None
Product: Base System
Classification: Unclassified
Component: kern (show other bugs)
Version: Unspecified
Hardware: Any Any
: --- Affects Only Me
Assignee: Alexander V. Chernikov
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2020-09-11 22:38 UTC by Demi M. Obenour
Modified: 2020-09-14 17:26 UTC (History)
2 users (show)

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Demi M. Obenour 2020-09-11 22:38:22 UTC
If an RTM_ADD command on a routing socket includes an RTA_IFA sockaddr,
and that sockaddr is an exact match for one of the interfaces in the
relevant routing domain, the RTA_IFP sockaddr is ignored.  If there are
multiple interfaces with the same IP address, this can cause packets to
be sent out the wrong interface.

I expected that an RTA_IFP sockaddr will always be honored.  That is,
the route will always use the interface supplied, regardless of what the
other sockaddrs in the message are.  If the kernel is not able to ensure
this, it should return an error.

I found this bug on OpenBSD.  I don’t have access to a FreeBSD machine, but a cursory look at the source code [1] indicates that FreeBSD likely has the same bug, so I decided to report it just in case.  I did manage to create a shell script that reproduces the bug:

	# replace these by any unused Ethernet pseudo-interfaces
	IF1=tap0 IF2=tap1
	ifconfig "$IF1" destroy 2>/dev/null
	ifconfig "$IF2" destroy 2>/dev/null
	dummy_mac=fe:ff:ff:ff:ff:ff dummy_ip=192.0.2.5
	ifconfig vether0 create lladdr "$dummy_mac"
	ifconfig "$IF2" create lladdr "$dummy_mac"
	ifconfig vether0 inet "$dummy_ip" prefixlen 32
	route -n delete "$dummy_ip/32" "$dummy_ip"
	ifconfig "$IF2" inet "$dummy_ip" prefixlen 32
	route -n delete "$dummy_ip/32" "$dummy_ip"
	route -n add -inet 192.0.2.6 -static -iface -llinfo -link "$IF2" -ifp vether1 -inet -ifa "$dummy_ip"
	route -n show -inet

If the bug affects FreeBSD, the route to 192.0.2.6 will be via $IF2, whereas if the bug does not affect FreeBSD, it will be via $IF1.

[1]: https://github.com/freebsd/freebsd/blob/9b858c384885d7431a5c82ec28d6142d142c8bbd/sys/net/route.c#L644-L645