I found a problem in the routing socket interface address install message.
This issue only happens when installing IPv4 addresses on interfaces
without specifying a prefix.

e.g. ifconfig vether0 1.1.1.1

The command above causes the installation of this address in the
'vether0' interface and sending a routing message 'RTM_NEWADDR' to all
routing daemons listening to the routing socket. The message generated
by the command above does not contain the prefix information, so the
daemons listening will receive a new address with prefixlen value set to
'0'.

The problem is that the prefix is not really '0', it was just not filled
in this case, so when you remove the above address from the interface the
next message that the routing daemons will receive will be a RTM_DELADDR
with a prefixlen of whatever class is the address that you installed
(in the case of the previous example, it would be '8'). Since some of
the routing daemons will consider the prefixlen to match the routes, this
route would never be deleted from these daemons.

This problem doesn't happen with IPv6 and you can check this by looking
at the route monitor output or by debugging routing daemon installed
addresses.

I've made a diff that fixes this problem for me. I just moved the mask
calculation to somewhere before rt_ifa_addlocal(), which is the function
responsible for calling the RTM_NEWADDR message.

Index: sys/netinet/in.c
===================================================================
RCS file: /home/obsdcvs/src/sys/netinet/in.c,v
retrieving revision 1.135
diff -u -p -r1.135 in.c
--- sys/netinet/in.c    16 Feb 2017 10:15:12 -0000      1.135
+++ sys/netinet/in.c    24 Mar 2017 16:46:27 -0000
@@ -614,6 +614,16 @@ in_ifinit(struct ifnet *ifp, struct in_i
        oldaddr = ia->ia_addr;
        ia->ia_addr = *sin;
 
+       if (ia->ia_netmask == 0) {
+               if (IN_CLASSA(i))
+                       ia->ia_netmask = IN_CLASSA_NET;
+               else if (IN_CLASSB(i))
+                       ia->ia_netmask = IN_CLASSB_NET;
+               else
+                       ia->ia_netmask = IN_CLASSC_NET;
+               ia->ia_sockmask.sin_addr.s_addr = ia->ia_netmask;
+       }
+
        /*
         * Give the interface a chance to initialize
         * if this is its first address,
@@ -641,15 +651,6 @@ in_ifinit(struct ifnet *ifp, struct in_i
        if (error)
                goto out;
 
-       if (ia->ia_netmask == 0) {
-               if (IN_CLASSA(i))
-                       ia->ia_netmask = IN_CLASSA_NET;
-               else if (IN_CLASSB(i))
-                       ia->ia_netmask = IN_CLASSB_NET;
-               else
-                       ia->ia_netmask = IN_CLASSC_NET;
-               ia->ia_sockmask.sin_addr.s_addr = ia->ia_netmask;
-       }
 
        ia->ia_net = i & ia->ia_netmask;
        in_socktrim(&ia->ia_sockmask);

Reply via email to