Bug 16318 - Fix for wrong interface when adding new routes
Summary: Fix for wrong interface when adding new routes
Status: Closed FIXED
Alias: None
Product: Base System
Classification: Unclassified
Component: kern (show other bugs)
Version: 3.4-STABLE
Hardware: Any Any
: Normal Affects Only Me
Assignee: freebsd-bugs (Nobody)
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2000-01-23 22:00 UTC by william.a
Modified: 2002-03-29 20:20 UTC (History)
0 users

See Also:


Attachments
file.diff (1.60 KB, patch)
2000-01-23 22:00 UTC, william.a
no flags Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description william.a 2000-01-23 22:00:01 UTC
 The kernel code in src/sys/net/route.c depends on the interfaces to know 
 where addresses go.  This can cause dubious error reporting and inappropriate
 routing if the routing table contains information that the interfaces 
 themselves don't know about.

 The following patch corrects ifa_ifwithroute() so in certain circumstances
 it will query the routing table in an appropriate fashion in case the
 desired gateway is on a interface that doesn't know it.
 
 This also helps resolve problems of multiple interfaces on the same network
 or on subnetworks of one another.  In these cases the kernel routing table
 will trump all information from the interfaces as to where things should be
 headed for new entries, unless the user specifically states otherwise.
 
 This has been tested with no ill effects on a variety of 3.4-release and stable
 machines.  It looks like the patch could also be relevant to -current OpenBSD
 and NetBSD.

 - William Carrel

How-To-Repeat: 
ifconfig xx0 10.0.0.1 netmask 255.255.255.0
route add 10.0.1.1/32 -interface xx0 -cloning
route add default 10.0.1.1

This will throw a "No route to host" error without the patch, with the patch
the kernel routing table will be checked and it will properly set the default
gateway to 10.0.1.1 on xx0.
Comment 1 Steve Price freebsd_committer freebsd_triage 2000-01-24 04:08:26 UTC
Responsible Changed
From-To: gnats-admin->freebsd-bugs

Misfiled PR. 

Comment 2 william.a 2000-02-15 10:31:08 UTC
This patch is applicable for both FreeBSD-stable AND FreeBSD-current, as
well as OpenBSD and NetBSD.  It has no noticeable ill-effects on the
machines of nearly a dozen FreeBSD users that have been testing the patch
for me.  Nor does it have ill effects on the OpenBSD and NetBSD machines I
have access to.

It fixes some brain-dead behavior of the kernel routing table on all these
operating systems.  It causes the routing table to check itself for the ifa
to assign to new routes before asking the interfaces.  There are occasions
(such as Ethernet point to point links) where the interfaces' idea of where
a packet should go could disagree with the routing tables user made static
entries.  This leads to some very bizarre behavior for things like the
default gateway if they get their packets routed to the wrong interface.

The patch is available here:
http://www.FreeBSD.org/cgi/query-pr.cgi?pr=16318

I just thought I'd post this around again to draw attention to my open PR
with code included, and mention that I've had successful testing reports on
-current.

-- William Carrel
Comment 3 mjy 2000-02-15 11:45:41 UTC
This fixed a big problem for me. I had been wondering why it wasn't
possible to have the default gateway in a different (but connected)
network. This should be in the released kernel!
Comment 4 william.a 2000-06-08 09:28:31 UTC
This problem still affects the FreeBSD kernel in 4.0 and 5.0.

A patch file for 4.0-STABLE follows, I've tested this on 4.0-RELEASE and
4.0-STABLE (incl. SMP for what it's worth).

There is no difference between route.c at HEAD(5.0-current) and 
RELENG_4(4.0-stable) so this patch should work effectively in both of
the aforementioned.  And it does still fix my routing troubles.

(and this time I sent the PR followup to a qualified name.)

--- route.c.orig	Sat May 27 14:48:42 2000
+++ route.c	Sat May 27 15:01:43 2000
@@ -400,6 +400,9 @@
 	struct sockaddr	*dst, *gateway;
 {
 	register struct ifaddr *ifa;
+	struct rtentry *rt;
+
+	ifa = 0;
 	if ((flags & RTF_GATEWAY) == 0) {
 		/*
 		 * If we are adding a route to an interface,
@@ -408,7 +411,6 @@
 		 * as our clue to the interface.  Otherwise
 		 * we can use the local address.
 		 */
-		ifa = 0;
 		if (flags & RTF_HOST) {
 			ifa = ifa_ifwithdstaddr(dst);
 		}
@@ -425,18 +427,33 @@
 	if (ifa == 0)
 		ifa = ifa_ifwithnet(gateway);
 	if (ifa == 0) {
-		struct rtentry *rt = rtalloc1(dst, 0, 0UL);
-		if (rt == 0)
-			return (0);
-		rt->rt_refcnt--;
-		if ((ifa = rt->rt_ifa) == 0)
-			return (0);
+		rt = rtalloc1(dst, 0, 0UL);
+		if (rt) {
+			rt->rt_refcnt--;
+			if (rt->rt_ifa)
+				ifa = rt->rt_ifa;
+		}
 	}
-	if (ifa->ifa_addr->sa_family != dst->sa_family) {
+	if ((ifa) && (ifa->ifa_addr->sa_family != dst->sa_family)) {
 		struct ifaddr *oifa = ifa;
 		ifa = ifaof_ifpforaddr(dst, ifa->ifa_ifp);
 		if (ifa == 0)
 			ifa = oifa;
+	}
+	/* 
+	 * If we are adding a gateway, it is quite
+	 * possible that the routing table has a static
+	 * entry in place for the gateway, that may
+	 * not agree with the info from the interfaces.
+	 * The routing table should carry more precedence
+	 * than the interfaces in this matter.
+	 * Must be careful not to stomp on new entries from 
+	 * rtinit, hence (ifa->ifa_addr !=gateway).
+	 */
+	if ((ifa == 0 || ifa->ifa_addr != gateway) &&
+			(rt = rtalloc1(gateway,0,0UL))) {
+		rt->rt_refcnt--;
+		ifa = rt->rt_ifa;
 	}
 	return (ifa);
 }

----- End forwarded message -----
Comment 5 Mike Barcroft freebsd_committer freebsd_triage 2001-07-21 20:05:35 UTC
State Changed
From-To: open->feedback


Does this problem still occur in newer versions of FreeBSD, 
such as 4.3-RELEASE?
Comment 6 Sheldon Hearn freebsd_committer freebsd_triage 2002-01-18 16:14:39 UTC
State Changed
From-To: feedback->closed

Automatic feedback timeout.  If additional feedback that warrants 
the re-opening of this PR is available but not included in the 
audit trail, please include the feedback in a reply to this message 
(preserving the Subject line) and ask that the PR be re-opened.
Comment 7 william.carrel 2002-03-29 20:18:30 UTC
I can confirm that this problem still occurs in RELENG_4.

I'm not sure if the patch I provided is still valid.

To reproduce on a system with two interfaces...

ifconfig if0 10.0.1.0 -netmask 255.255.255.0
ifconfig if1 10.0.2.0 -netmask 255.255.255.0
route add 10.0.2.1 -interface if0
route add default 10.0.2.1

netstat -rnfinet will show that the default route points toward if1 even 
though a static route for 10.0.2.1 shows it should be going to if0.  
Since the route add default won't take an -interface argument it gets a 
little difficult to handle.

The patch provided against the ancient version fixed it there.  I'm not 
sure how much that code has changed in the past year or two.

p.s. apologies for the late reply