mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-25 21:24:08 +08:00
[XFRM]: Fix wildcard as tunnel source
Hashing SAs by source address breaks templates with wildcards as tunnel source since the source address used for hashing/lookup is still 0/0. Move source address lookup to xfrm_tmpl_resolve_one() so we can use the real address in the lookup. Signed-off-by: Patrick McHardy <kaber@trash.net> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
1ef9696c90
commit
a1e59abf82
@ -222,6 +222,7 @@ struct xfrm_policy_afinfo {
|
|||||||
struct dst_ops *dst_ops;
|
struct dst_ops *dst_ops;
|
||||||
void (*garbage_collect)(void);
|
void (*garbage_collect)(void);
|
||||||
int (*dst_lookup)(struct xfrm_dst **dst, struct flowi *fl);
|
int (*dst_lookup)(struct xfrm_dst **dst, struct flowi *fl);
|
||||||
|
int (*get_saddr)(xfrm_address_t *saddr, xfrm_address_t *daddr);
|
||||||
struct dst_entry *(*find_bundle)(struct flowi *fl, struct xfrm_policy *policy);
|
struct dst_entry *(*find_bundle)(struct flowi *fl, struct xfrm_policy *policy);
|
||||||
int (*bundle_create)(struct xfrm_policy *policy,
|
int (*bundle_create)(struct xfrm_policy *policy,
|
||||||
struct xfrm_state **xfrm,
|
struct xfrm_state **xfrm,
|
||||||
@ -630,6 +631,18 @@ secpath_reset(struct sk_buff *skb)
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline int
|
||||||
|
xfrm_addr_any(xfrm_address_t *addr, unsigned short family)
|
||||||
|
{
|
||||||
|
switch (family) {
|
||||||
|
case AF_INET:
|
||||||
|
return addr->a4 == 0;
|
||||||
|
case AF_INET6:
|
||||||
|
return ipv6_addr_any((struct in6_addr *)&addr->a6);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static inline int
|
static inline int
|
||||||
__xfrm4_state_addr_cmp(struct xfrm_tmpl *tmpl, struct xfrm_state *x)
|
__xfrm4_state_addr_cmp(struct xfrm_tmpl *tmpl, struct xfrm_state *x)
|
||||||
{
|
{
|
||||||
|
@ -21,6 +21,25 @@ static int xfrm4_dst_lookup(struct xfrm_dst **dst, struct flowi *fl)
|
|||||||
return __ip_route_output_key((struct rtable**)dst, fl);
|
return __ip_route_output_key((struct rtable**)dst, fl);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int xfrm4_get_saddr(xfrm_address_t *saddr, xfrm_address_t *daddr)
|
||||||
|
{
|
||||||
|
struct rtable *rt;
|
||||||
|
struct flowi fl_tunnel = {
|
||||||
|
.nl_u = {
|
||||||
|
.ip4_u = {
|
||||||
|
.daddr = daddr->a4,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!xfrm4_dst_lookup((struct xfrm_dst **)&rt, &fl_tunnel)) {
|
||||||
|
saddr->a4 = rt->rt_src;
|
||||||
|
dst_release(&rt->u.dst);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return -EHOSTUNREACH;
|
||||||
|
}
|
||||||
|
|
||||||
static struct dst_entry *
|
static struct dst_entry *
|
||||||
__xfrm4_find_bundle(struct flowi *fl, struct xfrm_policy *policy)
|
__xfrm4_find_bundle(struct flowi *fl, struct xfrm_policy *policy)
|
||||||
{
|
{
|
||||||
@ -298,6 +317,7 @@ static struct xfrm_policy_afinfo xfrm4_policy_afinfo = {
|
|||||||
.family = AF_INET,
|
.family = AF_INET,
|
||||||
.dst_ops = &xfrm4_dst_ops,
|
.dst_ops = &xfrm4_dst_ops,
|
||||||
.dst_lookup = xfrm4_dst_lookup,
|
.dst_lookup = xfrm4_dst_lookup,
|
||||||
|
.get_saddr = xfrm4_get_saddr,
|
||||||
.find_bundle = __xfrm4_find_bundle,
|
.find_bundle = __xfrm4_find_bundle,
|
||||||
.bundle_create = __xfrm4_bundle_create,
|
.bundle_create = __xfrm4_bundle_create,
|
||||||
.decode_session = _decode_session4,
|
.decode_session = _decode_session4,
|
||||||
|
@ -42,21 +42,6 @@ __xfrm4_init_tempsel(struct xfrm_state *x, struct flowi *fl,
|
|||||||
x->props.saddr = tmpl->saddr;
|
x->props.saddr = tmpl->saddr;
|
||||||
if (x->props.saddr.a4 == 0)
|
if (x->props.saddr.a4 == 0)
|
||||||
x->props.saddr.a4 = saddr->a4;
|
x->props.saddr.a4 = saddr->a4;
|
||||||
if (tmpl->mode == XFRM_MODE_TUNNEL && x->props.saddr.a4 == 0) {
|
|
||||||
struct rtable *rt;
|
|
||||||
struct flowi fl_tunnel = {
|
|
||||||
.nl_u = {
|
|
||||||
.ip4_u = {
|
|
||||||
.daddr = x->id.daddr.a4,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
if (!xfrm_dst_lookup((struct xfrm_dst **)&rt,
|
|
||||||
&fl_tunnel, AF_INET)) {
|
|
||||||
x->props.saddr.a4 = rt->rt_src;
|
|
||||||
dst_release(&rt->u.dst);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
x->props.mode = tmpl->mode;
|
x->props.mode = tmpl->mode;
|
||||||
x->props.reqid = tmpl->reqid;
|
x->props.reqid = tmpl->reqid;
|
||||||
x->props.family = AF_INET;
|
x->props.family = AF_INET;
|
||||||
|
@ -34,6 +34,26 @@ static int xfrm6_dst_lookup(struct xfrm_dst **dst, struct flowi *fl)
|
|||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int xfrm6_get_saddr(xfrm_address_t *saddr, xfrm_address_t *daddr)
|
||||||
|
{
|
||||||
|
struct rt6_info *rt;
|
||||||
|
struct flowi fl_tunnel = {
|
||||||
|
.nl_u = {
|
||||||
|
.ip6_u = {
|
||||||
|
.daddr = *(struct in6_addr *)&daddr->a6,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!xfrm6_dst_lookup((struct xfrm_dst **)&rt, &fl_tunnel)) {
|
||||||
|
ipv6_get_saddr(&rt->u.dst, (struct in6_addr *)&daddr->a6,
|
||||||
|
(struct in6_addr *)&saddr->a6);
|
||||||
|
dst_release(&rt->u.dst);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return -EHOSTUNREACH;
|
||||||
|
}
|
||||||
|
|
||||||
static struct dst_entry *
|
static struct dst_entry *
|
||||||
__xfrm6_find_bundle(struct flowi *fl, struct xfrm_policy *policy)
|
__xfrm6_find_bundle(struct flowi *fl, struct xfrm_policy *policy)
|
||||||
{
|
{
|
||||||
@ -362,6 +382,7 @@ static struct xfrm_policy_afinfo xfrm6_policy_afinfo = {
|
|||||||
.family = AF_INET6,
|
.family = AF_INET6,
|
||||||
.dst_ops = &xfrm6_dst_ops,
|
.dst_ops = &xfrm6_dst_ops,
|
||||||
.dst_lookup = xfrm6_dst_lookup,
|
.dst_lookup = xfrm6_dst_lookup,
|
||||||
|
.get_saddr = xfrm6_get_saddr,
|
||||||
.find_bundle = __xfrm6_find_bundle,
|
.find_bundle = __xfrm6_find_bundle,
|
||||||
.bundle_create = __xfrm6_bundle_create,
|
.bundle_create = __xfrm6_bundle_create,
|
||||||
.decode_session = _decode_session6,
|
.decode_session = _decode_session6,
|
||||||
|
@ -42,22 +42,6 @@ __xfrm6_init_tempsel(struct xfrm_state *x, struct flowi *fl,
|
|||||||
memcpy(&x->props.saddr, &tmpl->saddr, sizeof(x->props.saddr));
|
memcpy(&x->props.saddr, &tmpl->saddr, sizeof(x->props.saddr));
|
||||||
if (ipv6_addr_any((struct in6_addr*)&x->props.saddr))
|
if (ipv6_addr_any((struct in6_addr*)&x->props.saddr))
|
||||||
memcpy(&x->props.saddr, saddr, sizeof(x->props.saddr));
|
memcpy(&x->props.saddr, saddr, sizeof(x->props.saddr));
|
||||||
if (tmpl->mode == XFRM_MODE_TUNNEL && ipv6_addr_any((struct in6_addr*)&x->props.saddr)) {
|
|
||||||
struct rt6_info *rt;
|
|
||||||
struct flowi fl_tunnel = {
|
|
||||||
.nl_u = {
|
|
||||||
.ip6_u = {
|
|
||||||
.daddr = *(struct in6_addr *)daddr,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
if (!xfrm_dst_lookup((struct xfrm_dst **)&rt,
|
|
||||||
&fl_tunnel, AF_INET6)) {
|
|
||||||
ipv6_get_saddr(&rt->u.dst, (struct in6_addr *)daddr,
|
|
||||||
(struct in6_addr *)&x->props.saddr);
|
|
||||||
dst_release(&rt->u.dst);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
x->props.mode = tmpl->mode;
|
x->props.mode = tmpl->mode;
|
||||||
x->props.reqid = tmpl->reqid;
|
x->props.reqid = tmpl->reqid;
|
||||||
x->props.family = AF_INET6;
|
x->props.family = AF_INET6;
|
||||||
|
@ -1107,6 +1107,20 @@ int __xfrm_sk_clone_policy(struct sock *sk)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
xfrm_get_saddr(xfrm_address_t *local, xfrm_address_t *remote,
|
||||||
|
unsigned short family)
|
||||||
|
{
|
||||||
|
int err;
|
||||||
|
struct xfrm_policy_afinfo *afinfo = xfrm_policy_get_afinfo(family);
|
||||||
|
|
||||||
|
if (unlikely(afinfo == NULL))
|
||||||
|
return -EINVAL;
|
||||||
|
err = afinfo->get_saddr(local, remote);
|
||||||
|
xfrm_policy_put_afinfo(afinfo);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
/* Resolve list of templates for the flow, given policy. */
|
/* Resolve list of templates for the flow, given policy. */
|
||||||
|
|
||||||
static int
|
static int
|
||||||
@ -1118,6 +1132,7 @@ xfrm_tmpl_resolve_one(struct xfrm_policy *policy, struct flowi *fl,
|
|||||||
int i, error;
|
int i, error;
|
||||||
xfrm_address_t *daddr = xfrm_flowi_daddr(fl, family);
|
xfrm_address_t *daddr = xfrm_flowi_daddr(fl, family);
|
||||||
xfrm_address_t *saddr = xfrm_flowi_saddr(fl, family);
|
xfrm_address_t *saddr = xfrm_flowi_saddr(fl, family);
|
||||||
|
xfrm_address_t tmp;
|
||||||
|
|
||||||
for (nx=0, i = 0; i < policy->xfrm_nr; i++) {
|
for (nx=0, i = 0; i < policy->xfrm_nr; i++) {
|
||||||
struct xfrm_state *x;
|
struct xfrm_state *x;
|
||||||
@ -1128,6 +1143,12 @@ xfrm_tmpl_resolve_one(struct xfrm_policy *policy, struct flowi *fl,
|
|||||||
if (tmpl->mode == XFRM_MODE_TUNNEL) {
|
if (tmpl->mode == XFRM_MODE_TUNNEL) {
|
||||||
remote = &tmpl->id.daddr;
|
remote = &tmpl->id.daddr;
|
||||||
local = &tmpl->saddr;
|
local = &tmpl->saddr;
|
||||||
|
if (xfrm_addr_any(local, family)) {
|
||||||
|
error = xfrm_get_saddr(&tmp, remote, family);
|
||||||
|
if (error)
|
||||||
|
goto fail;
|
||||||
|
local = &tmp;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
x = xfrm_state_find(remote, local, fl, tmpl, policy, &error, family);
|
x = xfrm_state_find(remote, local, fl, tmpl, policy, &error, family);
|
||||||
|
Loading…
Reference in New Issue
Block a user