Do not automatically install routes to link-local and interface-local multicast

addresses.

Obtained from:	Yandex LLC
Sponsored by:	Yandex LLC
This commit is contained in:
Andrey V. Elsukov 2014-10-27 16:15:15 +00:00
parent 219b3e3a0c
commit c56173a626
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=273742

View File

@ -782,27 +782,24 @@ in6_update_ifa_join_mc(struct ifnet *ifp, struct in6_aliasreq *ifra,
struct in6_ifaddr *ia, int flags, struct in6_multi **in6m_sol)
{
char ip6buf[INET6_ADDRSTRLEN];
struct sockaddr_in6 mltaddr, mltmask;
struct in6_addr llsol;
struct in6_addr mltaddr;
struct in6_multi_mship *imm;
struct rtentry *rt;
int delay, error;
KASSERT(in6m_sol != NULL, ("%s: in6m_sol is NULL", __func__));
/* Join solicited multicast addr for new host id. */
bzero(&llsol, sizeof(struct in6_addr));
llsol.s6_addr32[0] = IPV6_ADDR_INT32_MLL;
llsol.s6_addr32[1] = 0;
llsol.s6_addr32[2] = htonl(1);
llsol.s6_addr32[3] = ifra->ifra_addr.sin6_addr.s6_addr32[3];
llsol.s6_addr8[12] = 0xff;
if ((error = in6_setscope(&llsol, ifp, NULL)) != 0) {
bzero(&mltaddr, sizeof(struct in6_addr));
mltaddr.s6_addr32[0] = IPV6_ADDR_INT32_MLL;
mltaddr.s6_addr32[2] = htonl(1);
mltaddr.s6_addr32[3] = ifra->ifra_addr.sin6_addr.s6_addr32[3];
mltaddr.s6_addr8[12] = 0xff;
if ((error = in6_setscope(&mltaddr, ifp, NULL)) != 0) {
/* XXX: should not happen */
log(LOG_ERR, "%s: in6_setscope failed\n", __func__);
goto cleanup;
}
delay = 0;
delay = error = 0;
if ((flags & IN6_IFAUPDATE_DADDELAY)) {
/*
* We need a random delay for DAD on the address being
@ -812,62 +809,28 @@ in6_update_ifa_join_mc(struct ifnet *ifp, struct in6_aliasreq *ifra,
*/
delay = arc4random() % (MAX_RTR_SOLICITATION_DELAY * hz);
}
imm = in6_joingroup(ifp, &llsol, &error, delay);
imm = in6_joingroup(ifp, &mltaddr, &error, delay);
if (imm == NULL) {
nd6log((LOG_WARNING, "%s: addmulti failed for %s on %s "
"(errno=%d)\n", __func__, ip6_sprintf(ip6buf, &llsol),
nd6log((LOG_WARNING, "%s: in6_joingroup failed for %s on %s "
"(errno=%d)\n", __func__, ip6_sprintf(ip6buf, &mltaddr),
if_name(ifp), error));
goto cleanup;
}
LIST_INSERT_HEAD(&ia->ia6_memberships, imm, i6mm_chain);
*in6m_sol = imm->i6mm_maddr;
bzero(&mltmask, sizeof(mltmask));
mltmask.sin6_len = sizeof(struct sockaddr_in6);
mltmask.sin6_family = AF_INET6;
mltmask.sin6_addr = in6mask32;
#define MLTMASK_LEN 4 /* mltmask's masklen (=32bit=4octet) */
/*
* Join link-local all-nodes address.
*/
bzero(&mltaddr, sizeof(mltaddr));
mltaddr.sin6_len = sizeof(struct sockaddr_in6);
mltaddr.sin6_family = AF_INET6;
mltaddr.sin6_addr = in6addr_linklocal_allnodes;
if ((error = in6_setscope(&mltaddr.sin6_addr, ifp, NULL)) != 0)
mltaddr = in6addr_linklocal_allnodes;
if ((error = in6_setscope(&mltaddr, ifp, NULL)) != 0)
goto cleanup; /* XXX: should not fail */
/*
* XXX: do we really need this automatic routes? We should probably
* reconsider this stuff. Most applications actually do not need the
* routes, since they usually specify the outgoing interface.
*/
rt = in6_rtalloc1((struct sockaddr *)&mltaddr, 0, 0UL, RT_DEFAULT_FIB);
if (rt != NULL) {
/* XXX: only works in !SCOPEDROUTING case. */
if (memcmp(&mltaddr.sin6_addr,
&((struct sockaddr_in6 *)rt_key(rt))->sin6_addr,
MLTMASK_LEN)) {
RTFREE_LOCKED(rt);
rt = NULL;
}
}
if (rt == NULL) {
error = in6_rtrequest(RTM_ADD, (struct sockaddr *)&mltaddr,
(struct sockaddr *)&ia->ia_addr,
(struct sockaddr *)&mltmask, RTF_UP,
(struct rtentry **)0, RT_DEFAULT_FIB);
if (error)
goto cleanup;
} else
RTFREE_LOCKED(rt);
imm = in6_joingroup(ifp, &mltaddr.sin6_addr, &error, 0);
imm = in6_joingroup(ifp, &mltaddr, &error, 0);
if (imm == NULL) {
nd6log((LOG_WARNING, "%s: addmulti failed for %s on %s "
"(errno=%d)\n", __func__, ip6_sprintf(ip6buf,
&mltaddr.sin6_addr), if_name(ifp), error));
nd6log((LOG_WARNING, "%s: in6_joingroup failed for %s on %s "
"(errno=%d)\n", __func__, ip6_sprintf(ip6buf, &mltaddr),
if_name(ifp), error));
goto cleanup;
}
LIST_INSERT_HEAD(&ia->ia6_memberships, imm, i6mm_chain);
@ -883,24 +846,26 @@ in6_update_ifa_join_mc(struct ifnet *ifp, struct in6_aliasreq *ifra,
*/
delay = arc4random() % (MAX_RTR_SOLICITATION_DELAY * hz);
}
if (in6_nigroup(ifp, NULL, -1, &mltaddr.sin6_addr) == 0) {
if (in6_nigroup(ifp, NULL, -1, &mltaddr) == 0) {
/* XXX jinmei */
imm = in6_joingroup(ifp, &mltaddr.sin6_addr, &error, delay);
imm = in6_joingroup(ifp, &mltaddr, &error, delay);
if (imm == NULL)
nd6log((LOG_WARNING, "%s: addmulti failed for %s on %s "
nd6log((LOG_WARNING,
"%s: in6_joingroup failed for %s on %s "
"(errno=%d)\n", __func__, ip6_sprintf(ip6buf,
&mltaddr.sin6_addr), if_name(ifp), error));
&mltaddr), if_name(ifp), error));
/* XXX not very fatal, go on... */
else
LIST_INSERT_HEAD(&ia->ia6_memberships, imm, i6mm_chain);
}
if (V_icmp6_nodeinfo_oldmcprefix &&
in6_nigroup_oldmcprefix(ifp, NULL, -1, &mltaddr.sin6_addr) == 0) {
imm = in6_joingroup(ifp, &mltaddr.sin6_addr, &error, delay);
if (V_icmp6_nodeinfo_oldmcprefix &&
in6_nigroup_oldmcprefix(ifp, NULL, -1, &mltaddr) == 0) {
imm = in6_joingroup(ifp, &mltaddr, &error, delay);
if (imm == NULL)
nd6log((LOG_WARNING, "%s: addmulti failed for %s on %s "
nd6log((LOG_WARNING,
"%s: in6_joingroup failed for %s on %s "
"(errno=%d)\n", __func__, ip6_sprintf(ip6buf,
&mltaddr.sin6_addr), if_name(ifp), error));
&mltaddr), if_name(ifp), error));
/* XXX not very fatal, go on... */
else
LIST_INSERT_HEAD(&ia->ia6_memberships, imm, i6mm_chain);
@ -910,38 +875,18 @@ in6_update_ifa_join_mc(struct ifnet *ifp, struct in6_aliasreq *ifra,
* Join interface-local all-nodes address.
* (ff01::1%ifN, and ff01::%ifN/32)
*/
mltaddr.sin6_addr = in6addr_nodelocal_allnodes;
if ((error = in6_setscope(&mltaddr.sin6_addr, ifp, NULL)) != 0)
mltaddr = in6addr_nodelocal_allnodes;
if ((error = in6_setscope(&mltaddr, ifp, NULL)) != 0)
goto cleanup; /* XXX: should not fail */
/* XXX: again, do we really need the route? */
rt = in6_rtalloc1((struct sockaddr *)&mltaddr, 0, 0UL, RT_DEFAULT_FIB);
if (rt != NULL) {
if (memcmp(&mltaddr.sin6_addr,
&((struct sockaddr_in6 *)rt_key(rt))->sin6_addr,
MLTMASK_LEN)) {
RTFREE_LOCKED(rt);
rt = NULL;
}
}
if (rt == NULL) {
error = in6_rtrequest(RTM_ADD, (struct sockaddr *)&mltaddr,
(struct sockaddr *)&ia->ia_addr,
(struct sockaddr *)&mltmask, RTF_UP,
(struct rtentry **)0, RT_DEFAULT_FIB);
if (error)
goto cleanup;
} else
RTFREE_LOCKED(rt);
imm = in6_joingroup(ifp, &mltaddr.sin6_addr, &error, 0);
imm = in6_joingroup(ifp, &mltaddr, &error, 0);
if (imm == NULL) {
nd6log((LOG_WARNING, "%s: addmulti failed for %s on %s "
nd6log((LOG_WARNING, "%s: in6_joingroup failed for %s on %s "
"(errno=%d)\n", __func__, ip6_sprintf(ip6buf,
&mltaddr.sin6_addr), if_name(ifp), error));
&mltaddr), if_name(ifp), error));
goto cleanup;
}
LIST_INSERT_HEAD(&ia->ia6_memberships, imm, i6mm_chain);
#undef MLTMASK_LEN
cleanup:
return (error);
@ -1343,135 +1288,17 @@ in6_broadcast_ifa(struct ifnet *ifp, struct in6_aliasreq *ifra,
}
/*
* Leave multicast groups. Factored out from in6_purgeaddr().
* This entire work should only be done once, for the default FIB.
* Leave from multicast groups we have joined for the interface.
*/
static int
in6_purgeaddr_mc(struct ifnet *ifp, struct in6_ifaddr *ia, struct ifaddr *ifa0)
{
struct sockaddr_in6 mltaddr, mltmask;
struct in6_multi_mship *imm;
struct rtentry *rt;
struct sockaddr_in6 sin6;
int error;
/*
* Leave from multicast groups we have joined for the interface.
*/
while ((imm = LIST_FIRST(&ia->ia6_memberships)) != NULL) {
LIST_REMOVE(imm, i6mm_chain);
in6_leavegroup(imm);
}
/*
* Remove the link-local all-nodes address.
*/
bzero(&mltmask, sizeof(mltmask));
mltmask.sin6_len = sizeof(struct sockaddr_in6);
mltmask.sin6_family = AF_INET6;
mltmask.sin6_addr = in6mask32;
bzero(&mltaddr, sizeof(mltaddr));
mltaddr.sin6_len = sizeof(struct sockaddr_in6);
mltaddr.sin6_family = AF_INET6;
mltaddr.sin6_addr = in6addr_linklocal_allnodes;
if ((error = in6_setscope(&mltaddr.sin6_addr, ifp, NULL)) != 0)
return (error);
/*
* As for the mltaddr above, proactively prepare the sin6 to avoid
* rtentry un- and re-locking.
*/
if (ifa0 != NULL) {
bzero(&sin6, sizeof(sin6));
sin6.sin6_len = sizeof(sin6);
sin6.sin6_family = AF_INET6;
memcpy(&sin6.sin6_addr, &satosin6(ifa0->ifa_addr)->sin6_addr,
sizeof(sin6.sin6_addr));
error = in6_setscope(&sin6.sin6_addr, ifa0->ifa_ifp, NULL);
if (error != 0)
return (error);
}
rt = in6_rtalloc1((struct sockaddr *)&mltaddr, 0, 0UL, RT_DEFAULT_FIB);
if (rt != NULL && rt->rt_gateway != NULL &&
(memcmp(&satosin6(rt->rt_gateway)->sin6_addr,
&ia->ia_addr.sin6_addr,
sizeof(ia->ia_addr.sin6_addr)) == 0)) {
/*
* If no more IPv6 address exists on this interface then
* remove the multicast address route.
*/
if (ifa0 == NULL) {
memcpy(&mltaddr.sin6_addr,
&satosin6(rt_key(rt))->sin6_addr,
sizeof(mltaddr.sin6_addr));
RTFREE_LOCKED(rt);
error = in6_rtrequest(RTM_DELETE,
(struct sockaddr *)&mltaddr,
(struct sockaddr *)&ia->ia_addr,
(struct sockaddr *)&mltmask, RTF_UP,
(struct rtentry **)0, RT_DEFAULT_FIB);
if (error)
log(LOG_INFO, "%s: link-local all-nodes "
"multicast address deletion error\n",
__func__);
} else {
/*
* Replace the gateway of the route.
*/
memcpy(rt->rt_gateway, &sin6, sizeof(sin6));
RTFREE_LOCKED(rt);
}
} else {
if (rt != NULL)
RTFREE_LOCKED(rt);
}
/*
* Remove the node-local all-nodes address.
*/
mltaddr.sin6_addr = in6addr_nodelocal_allnodes;
if ((error = in6_setscope(&mltaddr.sin6_addr, ifp, NULL)) != 0)
return (error);
rt = in6_rtalloc1((struct sockaddr *)&mltaddr, 0, 0UL, RT_DEFAULT_FIB);
if (rt != NULL && rt->rt_gateway != NULL &&
(memcmp(&satosin6(rt->rt_gateway)->sin6_addr,
&ia->ia_addr.sin6_addr,
sizeof(ia->ia_addr.sin6_addr)) == 0)) {
/*
* If no more IPv6 address exists on this interface then
* remove the multicast address route.
*/
if (ifa0 == NULL) {
memcpy(&mltaddr.sin6_addr,
&satosin6(rt_key(rt))->sin6_addr,
sizeof(mltaddr.sin6_addr));
RTFREE_LOCKED(rt);
error = in6_rtrequest(RTM_DELETE,
(struct sockaddr *)&mltaddr,
(struct sockaddr *)&ia->ia_addr,
(struct sockaddr *)&mltmask, RTF_UP,
(struct rtentry **)0, RT_DEFAULT_FIB);
if (error)
log(LOG_INFO, "%s: node-local all-nodes"
"multicast address deletion error\n",
__func__);
} else {
/*
* Replace the gateway of the route.
*/
memcpy(rt->rt_gateway, &sin6, sizeof(sin6));
RTFREE_LOCKED(rt);
}
} else {
if (rt != NULL)
RTFREE_LOCKED(rt);
}
return (0);
}