Subject: kern/15662: Routes not being cleaned up when interface addr changed.
To: None <gnats-bugs@gnats.netbsd.org>
From: None <seanb@qnx.com>
List: netbsd-bugs
Date: 02/18/2002 12:53:04
>Number: 15662
>Category: kern
>Synopsis: Routes not being cleaned up when interface addr changed.
>Confidential: no
>Severity: non-critical
>Priority: low
>Responsible: kern-bug-people
>State: open
>Class: sw-bug
>Submitter-Id: net
>Arrival-Date: Mon Feb 18 12:53:00 PST 2002
>Closed-Date:
>Last-Modified:
>Originator: Sean Boudreau
>Release: 1-5
>Organization:
QNX
>Environment:
NetBSD fili 1.5.1 NetBSD 1.5.1 (ker.xtang) #2: Mon Jul 30 09:33:07 EDT 2001
>Description:
When an interface address is deleted. Routes can still exist whose
rt->rt_ifa reference the old addr.
>How-To-Repeat:
Consider a host A whose default gateway is B:
# ifconfig ex0 10.0.0.25
# route add default 10.0.0.26
A(10.25) ------------- B(10.26) ---------- C(w.x.y.z)
# netstat -finet -rn
Routing tables
Internet:
Destination Gateway Flags Refs Use Mtu Interface
default 10.7.0.36 UGS 0 679 1500 ex0
10 link#3 UC 4 0 1500 ex0
127 127.0.0.1 UGRS 0 0 33228 lo0
127.0.0.1 127.0.0.1 UH 0 112 33228 lo0
A can ping C through B.
Now change A's addr to something on same subnet. The routing table
is the same which in itself is not a problem, but if you try the ping
again, the source address is the old one (from sniff).
# ifconfig ex0 10.24
>Fix:
Index: netinet/in.c
===================================================================
RCS file: /cvsroot/syssrc/sys/netinet/in.c,v
retrieving revision 1.61.4.3
diff -c -r1.61.4.3 in.c
*** in.c 2000/10/17 00:45:36 1.61.4.3
--- in.c 2002/02/18 20:47:39
***************
*** 113,118 ****
--- 113,119 ----
#include <sys/socketvar.h>
#include <sys/systm.h>
#include <sys/proc.h>
+ #include <sys/syslog.h>
#include <net/if.h>
#include <net/route.h>
***************
*** 552,563 ****
--- 553,581 ----
return (0);
}
+ static int
+ ifa_rt_walktree(struct radix_node *rn, void *v)
+ {
+ struct in_ifaddr *ia = (struct in_ifaddr *)v;
+ struct rtentry *rt = (struct rtentry *)rn;
+ int error;
+
+ if (rt->rt_ifa == &ia->ia_ifa) {
+ if (error = rtrequest(RTM_DELETE, rt_key(rt), rt->rt_gateway, rt_mask(rt), rt->rt_flags, NULL))
+ log(LOG_WARNING, "ifa_rt_walktree: unable to delete rtentry. error= %d", error);
+ else
+ IFAFREE(&ia->ia_ifa);
+ }
+ return 0;
+ }
+
void
in_purgeaddr(ifa, ifp)
struct ifaddr *ifa;
struct ifnet *ifp;
{
struct in_ifaddr *ia = (void *) ifa;
+ struct radix_node_head *rnh;
in_ifscrub(ifp, ia);
LIST_REMOVE(ia, ia_hash);
***************
*** 574,579 ****
--- 592,601 ----
ifp->if_output != if_nulloutput)
in_savemkludge(ia);
IFAFREE(&ia->ia_ifa);
+
+ if (rnh = rt_tables[AF_INET])
+ (*rnh->rnh_walktree)(rnh, ifa_rt_walktree, ifa);
+
in_setmaxmtu();
}
>Release-Note:
>Audit-Trail:
>Unformatted: