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: