Fix handling of scoped IPv6 addresses in IPSec code.
* in ipsec_encap() embed scope zone ids into link-local addresses in the new IPv6 header, this helps ip6_output() disambiguate the scope; * teach key_ismyaddr6() use in6_localip(). in6_localip() is less strict than key_sockaddrcmp(). It doesn't compare all fileds of struct sockaddr_in6, but it is faster and it should be safe, because all SA's data was checked for correctness. Also, since IPv6 link-local addresses in the &V_in6_ifaddrhead are stored in kernel-internal form, we need to embed scope zone id from SA into the address before calling in6_localip. * in ipsec_common_input() take scope zone id embedded in the address and use it to initialize sin6_scope_id, then use this sockaddr structure to lookup SA, because we keep addresses in the SADB without embedded scope zone id. Differential Revision: https://reviews.freebsd.org/D2304 Reviewed by: gnn Sponsored by: Yandex LLC
This commit is contained in:
parent
61f376155d
commit
1ae800e7a6
@ -195,6 +195,13 @@ ipsec_common_input(struct mbuf *m, int skip, int protoff, int af, int sproto)
|
||||
m_copydata(m, offsetof(struct ip6_hdr, ip6_dst),
|
||||
sizeof(struct in6_addr),
|
||||
(caddr_t) &dst_address.sin6.sin6_addr);
|
||||
/* We keep addresses in SADB without embedded scope id */
|
||||
if (IN6_IS_SCOPE_LINKLOCAL(&dst_address.sin6.sin6_addr)) {
|
||||
/* XXX: sa6_recoverscope() */
|
||||
dst_address.sin6.sin6_scope_id =
|
||||
ntohs(dst_address.sin6.sin6_addr.s6_addr16[1]);
|
||||
dst_address.sin6.sin6_addr.s6_addr16[1] = 0;
|
||||
}
|
||||
break;
|
||||
#endif /* INET6 */
|
||||
default:
|
||||
|
@ -503,7 +503,14 @@ ipsec_encap(struct mbuf **mp, struct secasindex *saidx)
|
||||
ip6->ip6_hlim = V_ip6_defhlim;
|
||||
ip6->ip6_nxt = proto;
|
||||
ip6->ip6_dst = saidx->dst.sin6.sin6_addr;
|
||||
/* For link-local address embed scope zone id */
|
||||
if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_dst))
|
||||
ip6->ip6_dst.s6_addr16[1] =
|
||||
htons(saidx->dst.sin6.sin6_scope_id & 0xffff);
|
||||
ip6->ip6_src = saidx->src.sin6.sin6_addr;
|
||||
if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_src))
|
||||
ip6->ip6_src.s6_addr16[1] =
|
||||
htons(saidx->src.sin6.sin6_scope_id & 0xffff);
|
||||
ip6->ip6_plen = htons((*mp)->m_pkthdr.len - sizeof(*ip6));
|
||||
ip_ecn_ingress(V_ip6_ipsec_ecn, &proto, &itos);
|
||||
ip6->ip6_flow |= htonl((uint32_t)proto << 20);
|
||||
|
@ -3856,48 +3856,19 @@ key_ismyaddr(struct sockaddr *sa)
|
||||
* compare my own address for IPv6.
|
||||
* 1: ours
|
||||
* 0: other
|
||||
* NOTE: derived ip6_input() in KAME. This is necessary to modify more.
|
||||
*/
|
||||
#include <netinet6/in6_var.h>
|
||||
|
||||
static int
|
||||
key_ismyaddr6(struct sockaddr_in6 *sin6)
|
||||
{
|
||||
struct in6_ifaddr *ia;
|
||||
#if 0
|
||||
struct in6_multi *in6m;
|
||||
#endif
|
||||
struct in6_addr in6;
|
||||
|
||||
IN6_IFADDR_RLOCK();
|
||||
TAILQ_FOREACH(ia, &V_in6_ifaddrhead, ia_link) {
|
||||
if (key_sockaddrcmp((struct sockaddr *)sin6,
|
||||
(struct sockaddr *)&ia->ia_addr, 0) == 0) {
|
||||
IN6_IFADDR_RUNLOCK();
|
||||
return 1;
|
||||
}
|
||||
if (!IN6_IS_SCOPE_LINKLOCAL(&sin6->sin6_addr))
|
||||
return (in6_localip(&sin6->sin6_addr));
|
||||
|
||||
#if 0
|
||||
/*
|
||||
* XXX Multicast
|
||||
* XXX why do we care about multlicast here while we don't care
|
||||
* about IPv4 multicast??
|
||||
* XXX scope
|
||||
*/
|
||||
in6m = NULL;
|
||||
IN6_LOOKUP_MULTI(sin6->sin6_addr, ia->ia_ifp, in6m);
|
||||
if (in6m) {
|
||||
IN6_IFADDR_RUNLOCK();
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
IN6_IFADDR_RUNLOCK();
|
||||
|
||||
/* loopback, just for safety */
|
||||
if (IN6_IS_ADDR_LOOPBACK(&sin6->sin6_addr))
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
/* Convert address into kernel-internal form */
|
||||
in6 = sin6->sin6_addr;
|
||||
in6.s6_addr16[1] = htons(sin6->sin6_scope_id & 0xffff);
|
||||
return (in6_localip(&in6));
|
||||
}
|
||||
#endif /*INET6*/
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user