summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authormelifaro <melifaro@FreeBSD.org>2014-05-08 11:56:06 +0000
committermelifaro <melifaro@FreeBSD.org>2014-05-08 11:56:06 +0000
commit4a170f05aac2077fa2f5ffeac81602b94665b996 (patch)
tree21c270f49448afc585cf16bd6f30f2249df5152e
parentb2936ab3df6fac9d0c863866eb4ec0dc54f95f19 (diff)
downloadFreeBSD-src-4a170f05aac2077fa2f5ffeac81602b94665b996.zip
FreeBSD-src-4a170f05aac2077fa2f5ffeac81602b94665b996.tar.gz
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
-rw-r--r--sbin/route/route.c2
-rw-r--r--sys/net/rtsock.c46
2 files changed, 38 insertions, 10 deletions
diff --git a/sbin/route/route.c b/sbin/route/route.c
index 794f143..9b3bb95 100644
--- a/sbin/route/route.c
+++ b/sbin/route/route.c
@@ -1727,8 +1727,6 @@ print_getmsg(struct rt_msghdr *rtm, int msglen, int fib)
(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])
diff --git a/sys/net/rtsock.c b/sys/net/rtsock.c
index 0533a3a..5748931 100644
--- a/sys/net/rtsock.c
+++ b/sys/net/rtsock.c
@@ -162,6 +162,8 @@ static int sysctl_ifmalist(int af, struct walkarg *w);
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 socket *so)
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, struct rt_addrinfo *rtinfo)
}
/*
+ * 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 *ifa, int fibnum)
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 *ifa, int fibnum)
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 *ifp, int error, struct rtentry *rt,
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, void *vw)
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, void *vw)
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)
OpenPOWER on IntegriCloud