From cysgod@mail.carrel.org  Sun Jan 23 13:57:19 2000
Return-Path: <cysgod@mail.carrel.org>
Received: from darjeeling.carrel.org (darjeeling.carrel.org [216.173.212.202])
	by hub.freebsd.org (Postfix) with SMTP id 6734914DA9
	for <FreeBSD-gnats-submit@freebsd.org>; Sun, 23 Jan 2000 13:57:18 -0800 (PST)
	(envelope-from cysgod@mail.carrel.org)
Received: (qmail 17159 invoked by uid 1000); 23 Jan 2000 21:57:17 -0000
Message-Id: <20000123215717.17158.qmail@mail.carrel.org>
Date: 23 Jan 2000 21:57:17 -0000
From: william.a@carrel.org
Sender: cysgod@mail.carrel.org
Reply-To: william.a@carrel.org
To: FreeBSD-gnats-submit@freebsd.org
Subject: Fix for wrong interface when adding new routes<Synopsis of the problem (one line)>
X-Send-Pr-Version: 3.2

>Number:         16318
>Category:       kern
>Synopsis:       Fix for wrong interface when adding new routes
>Confidential:   no
>Severity:       serious
>Priority:       medium
>Responsible:    freebsd-bugs
>State:          closed
>Quarter:        
>Keywords:       
>Date-Required:  
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Sun Jan 23 14:00:01 PST 2000
>Closed-Date:    Fri Jan 18 08:14:39 PST 2002
>Last-Modified:  Fri Mar 29 12:20:02 PST 2002
>Originator:     William A. Carrel
>Release:        FreeBSD 3.4-STABLE i386
>Organization:
>Environment:

FreeBSD darjeeling.carrel.org 3.4-STABLE FreeBSD 3.4-STABLE #29: Thu Jan 20 19:56:05 PST 2000     root@darjeeling.carrel.org:/usr/src/sys/compile/DARJEELING  i386
	

>Description:

 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.
	

>Fix:

--- src/sys/net/route.c.orig	Wed Jan 19 23:17:12 2000
+++ src/sys/net/route.c	Thu Jan 20 19:55:00 2000
@@ -398,6 +398,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,
@@ -406,7 +409,6 @@
 		 * as our clue to the interface.  Otherwise
 		 * we can use the local address.
 		 */
-		ifa = 0;
 		if (flags & RTF_HOST) {
 			ifa = ifa_ifwithdstaddr(dst);
 		}
@@ -423,18 +425,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 info garnered 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);
 }
	


>Release-Note:
>Audit-Trail:
Responsible-Changed-From-To: gnats-admin->freebsd-bugs 
Responsible-Changed-By: steve 
Responsible-Changed-When: Sun Jan 23 20:08:26 PST 2000 
Responsible-Changed-Why:  
Misfiled PR. 

From: William Carrel <william.a@carrel.org>
To: <freebsd-gnats-submit@FreeBSD.org>, <william.a@carrel.org>,
	<freebsd-net@freebsd.org>, <freebsd-hackers@freebsd.org>
Cc:  
Subject: Re: kern/16318: Fix for wrong interface when adding new routes
Date: Tue, 15 Feb 2000 02:31:08 -0800

 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
 
 

From: "Marinos J. Yannikos" <mjy@pobox.com>
To: freebsd-gnats-submit@FreeBSD.org, william.a@carrel.org
Cc:  
Subject: Re: kern/16318: Fix for wrong interface when adding new routes
Date: Tue, 15 Feb 2000 12:45:41 +0100

 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!
 

From: William Carrel <william.a@carrel.org>
To: freebsd-gnats-submit@freebsd.org
Cc:  
Subject: Re: kern/16318: Fix for wrong interface when adding new routes
Date: Thu, 8 Jun 2000 01:28:31 -0700

 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 -----
 
State-Changed-From-To: open->feedback 
State-Changed-By: mike 
State-Changed-When: Sat Jul 21 12:05:35 PDT 2001 
State-Changed-Why:  

Does this problem still occur in newer versions of FreeBSD, 
such as 4.3-RELEASE? 

http://www.FreeBSD.org/cgi/query-pr.cgi?pr=16318 
State-Changed-From-To: feedback->closed 
State-Changed-By: sheldonh 
State-Changed-When: Fri Jan 18 08:14:39 PST 2002 
State-Changed-Why:  
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. 

http://www.freebsd.org/cgi/query-pr.cgi?pr=16318 

From: William Carrel <william.carrel@infospace.com>
To: freebsd-gnats-submit@freebsd.org
Cc: william.a@carrel.org
Subject: Re: kern/16318: Fix for wrong interface when adding new routes
Date: Fri, 29 Mar 2002 12:18:30 -0800

 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
 
>Unformatted:
