Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 8 May 2014 11:56:06 +0000 (UTC)
From:      "Alexander V. Chernikov" <melifaro@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r265666 - in head: sbin/route sys/net
Message-ID:  <201405081156.s48Bu6fo076440@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
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)



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201405081156.s48Bu6fo076440>