Author: melifaro
Date: Thu May  8 11:56:06 2014
New Revision: 265666
URL: http://svnweb.freebsd.org/changeset/base/265666

Log:
  Fix incorrect netmasks being passed via rtsock.
  
  Since radix has been ignoring sa_family in passed sockaddrs,
  no one ever has bothered filling valid sa_family in netmasks.
  Additionally, radix adjusts sa_len field in every netmask not to
  compare zero bytes at all.
  
  This leads us to rt_mask with sa_family of AF_UNSPEC (-1) and
  arbitrary sa_len field (0 for default route, for example).
  
  However, rtsock have been passing that rt_mask intact for ages,
  requiring all rtsock consumers to make ther own local hacks.
  We even have unfixed on in base:
  
  do `route -n monitor` in one window and issue `route -n get addr`
  for some directly-connected address. You will probably see the following:
  
  got message of size 304 on Thu May  8 15:06:06 2014
  RTM_GET: Report Metrics: len 304, pid: 30493, seq 1, errno 0, 
flags:<UP,DONE,PINNED>
  locks:  inits:
  sockaddrs: <DST,GATEWAY,NETMASK,IFP,IFA>
   10.0.0.0 link#1 (255) ffff ffff ff em0:8.0.27.c5.29.d4 10.0.0.92
  _________________^^^^^^^^^^^^^^^^^^
  
  after the change:
  
  got message of size 312 on Thu May  8 15:44:07 2014
  RTM_GET: Report Metrics: len 312, pid: 2895, seq 1, errno 0, 
flags:<UP,DONE,PINNED>
  locks:  inits:
  sockaddrs: <DST,GATEWAY,NETMASK,IFP,IFA>
   10.0.0.0 link#1 255.255.255.0 em0:8.0.27.c5.29.d4 10.0.0.92
  _________________^^^^^^^^^^^^^^^^^^
  
  Sponsored by: Yandex LLC
  MFC after:    1 month

Modified:
  head/sbin/route/route.c
  head/sys/net/rtsock.c

Modified: head/sbin/route/route.c
==============================================================================
--- head/sbin/route/route.c     Thu May  8 08:37:32 2014        (r265665)
+++ head/sbin/route/route.c     Thu May  8 11:56:06 2014        (r265666)
@@ -1727,8 +1727,6 @@ print_getmsg(struct rt_msghdr *rtm, int 
            (sp[RTAX_IFP]->sa_family != AF_LINK ||
             ((struct sockaddr_dl *)(void *)sp[RTAX_IFP])->sdl_nlen == 0))
                        sp[RTAX_IFP] = NULL;
-       if (sp[RTAX_DST] && sp[RTAX_NETMASK])
-               sp[RTAX_NETMASK]->sa_family = sp[RTAX_DST]->sa_family; /* XXX */
        if (sp[RTAX_DST])
                (void)printf("destination: %s\n", routename(sp[RTAX_DST]));
        if (sp[RTAX_NETMASK])

Modified: head/sys/net/rtsock.c
==============================================================================
--- head/sys/net/rtsock.c       Thu May  8 08:37:32 2014        (r265665)
+++ head/sys/net/rtsock.c       Thu May  8 11:56:06 2014        (r265666)
@@ -162,6 +162,8 @@ static int  sysctl_ifmalist(int af, struc
 static int     route_output(struct mbuf *m, struct socket *so);
 static void    rt_getmetrics(const struct rtentry *rt, struct rt_metrics *out);
 static void    rt_dispatch(struct mbuf *, sa_family_t);
+static struct sockaddr *rtsock_fix_netmask(struct sockaddr *dst,
+                       struct sockaddr *smask, struct sockaddr_storage *dmask);
 
 static struct netisr_handler rtsock_nh = {
        .nh_name = "rtsock",
@@ -520,8 +522,8 @@ route_output(struct mbuf *m, struct sock
        struct rtentry *rt = NULL;
        struct radix_node_head *rnh;
        struct rt_addrinfo info;
-#ifdef INET6
        struct sockaddr_storage ss;
+#ifdef INET6
        struct sockaddr_in6 *sin6;
        int i, rti_need_deembed = 0;
 #endif
@@ -784,7 +786,8 @@ report:
                }
                info.rti_info[RTAX_DST] = rt_key(rt);
                info.rti_info[RTAX_GATEWAY] = rt->rt_gateway;
-               info.rti_info[RTAX_NETMASK] = rt_mask(rt);
+               info.rti_info[RTAX_NETMASK] = rtsock_fix_netmask(rt_key(rt),
+                   rt_mask(rt), &ss);
                info.rti_info[RTAX_GENMASK] = 0;
                if (rtm->rtm_addrs & (RTA_IFP | RTA_IFA)) {
                        ifp = rt->rt_ifp;
@@ -967,6 +970,25 @@ rt_xaddrs(caddr_t cp, caddr_t cplim, str
 }
 
 /*
+ * Fill in @dmask with valid netmask leaving original @smask
+ * intact. Mostly used with radix netmasks.
+ */
+static struct sockaddr *
+rtsock_fix_netmask(struct sockaddr *dst, struct sockaddr *smask,
+    struct sockaddr_storage *dmask)
+{
+       if (dst == NULL || smask == NULL)
+               return (NULL);
+
+       memset(dmask, 0, dst->sa_len);
+       memcpy(dmask, smask, smask->sa_len);
+       dmask->ss_len = dst->sa_len;
+       dmask->ss_family = dst->sa_family;
+
+       return ((struct sockaddr *)dmask);
+}
+
+/*
  * Used by the routing socket.
  */
 static struct mbuf *
@@ -1247,6 +1269,7 @@ rtsock_addrmsg(int cmd, struct ifaddr *i
        struct mbuf *m;
        struct ifa_msghdr *ifam;
        struct ifnet *ifp = ifa->ifa_ifp;
+       struct sockaddr_storage ss;
 
        if (V_route_cb.any_count == 0)
                return (0);
@@ -1256,7 +1279,8 @@ rtsock_addrmsg(int cmd, struct ifaddr *i
        bzero((caddr_t)&info, sizeof(info));
        info.rti_info[RTAX_IFA] = sa = ifa->ifa_addr;
        info.rti_info[RTAX_IFP] = ifp->if_addr->ifa_addr;
-       info.rti_info[RTAX_NETMASK] = ifa->ifa_netmask;
+       info.rti_info[RTAX_NETMASK] = rtsock_fix_netmask(
+           info.rti_info[RTAX_IFP], ifa->ifa_netmask, &ss);
        info.rti_info[RTAX_BRD] = ifa->ifa_dstaddr;
        if ((m = rt_msg1(ncmd, &info)) == NULL)
                return (ENOBUFS);
@@ -1295,13 +1319,14 @@ rtsock_routemsg(int cmd, struct ifnet *i
        struct sockaddr *sa;
        struct mbuf *m;
        struct rt_msghdr *rtm;
+       struct sockaddr_storage ss;
 
        if (V_route_cb.any_count == 0)
                return (0);
 
        bzero((caddr_t)&info, sizeof(info));
-       info.rti_info[RTAX_NETMASK] = rt_mask(rt);
        info.rti_info[RTAX_DST] = sa = rt_key(rt);
+       info.rti_info[RTAX_NETMASK] = rtsock_fix_netmask(sa, rt_mask(rt), &ss);
        info.rti_info[RTAX_GATEWAY] = rt->rt_gateway;
        if ((m = rt_msg1(cmd, &info)) == NULL)
                return (ENOBUFS);
@@ -1473,6 +1498,7 @@ sysctl_dumpentry(struct radix_node *rn, 
        struct rtentry *rt = (struct rtentry *)rn;
        int error = 0, size;
        struct rt_addrinfo info;
+       struct sockaddr_storage ss;
 
        if (w->w_op == NET_RT_FLAGS && !(rt->rt_flags & w->w_arg))
                return 0;
@@ -1483,7 +1509,8 @@ sysctl_dumpentry(struct radix_node *rn, 
        bzero((caddr_t)&info, sizeof(info));
        info.rti_info[RTAX_DST] = rt_key(rt);
        info.rti_info[RTAX_GATEWAY] = rt->rt_gateway;
-       info.rti_info[RTAX_NETMASK] = rt_mask(rt);
+       info.rti_info[RTAX_NETMASK] = rtsock_fix_netmask(rt_key(rt),
+           rt_mask(rt), &ss);
        info.rti_info[RTAX_GENMASK] = 0;
        if (rt->rt_ifp) {
                info.rti_info[RTAX_IFP] = rt->rt_ifp->if_addr->ifa_addr;
@@ -1659,6 +1686,7 @@ sysctl_iflist(int af, struct walkarg *w)
        struct ifaddr *ifa;
        struct rt_addrinfo info;
        int len, error = 0;
+       struct sockaddr_storage ss;
 
        bzero((caddr_t)&info, sizeof(info));
        IFNET_RLOCK_NOSLEEP();
@@ -1687,7 +1715,8 @@ sysctl_iflist(int af, struct walkarg *w)
                            ifa->ifa_addr) != 0)
                                continue;
                        info.rti_info[RTAX_IFA] = ifa->ifa_addr;
-                       info.rti_info[RTAX_NETMASK] = ifa->ifa_netmask;
+                       info.rti_info[RTAX_NETMASK] = rtsock_fix_netmask(
+                           ifa->ifa_addr, ifa->ifa_netmask, &ss);
                        info.rti_info[RTAX_BRD] = ifa->ifa_dstaddr;
                        error = rtsock_msg_buffer(RTM_NEWADDR, &info, w, &len);
                        if (error != 0)
@@ -1704,8 +1733,9 @@ sysctl_iflist(int af, struct walkarg *w)
                        }
                }
                IF_ADDR_RUNLOCK(ifp);
-               info.rti_info[RTAX_IFA] = info.rti_info[RTAX_NETMASK] =
-                       info.rti_info[RTAX_BRD] = NULL;
+               info.rti_info[RTAX_IFA] = NULL;
+               info.rti_info[RTAX_NETMASK] = NULL;
+               info.rti_info[RTAX_BRD] = NULL;
        }
 done:
        if (ifp != NULL)
_______________________________________________
svn-src-head@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to