netfilter: nat: propagate errors from xfrm_me_harder()

Propagate errors from ip_xfrm_me_harder() instead of returning EPERM in
all cases.

Signed-off-by: Patrick McHardy <kaber@trash.net>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
This commit is contained in:
Patrick McHardy 2013-04-05 06:41:12 +00:00 committed by Pablo Neira Ayuso
parent 58e35d1471
commit aaa795ad25
3 changed files with 27 additions and 16 deletions

View File

@ -176,6 +176,7 @@ nf_nat_ipv4_out(unsigned int hooknum,
#ifdef CONFIG_XFRM #ifdef CONFIG_XFRM
const struct nf_conn *ct; const struct nf_conn *ct;
enum ip_conntrack_info ctinfo; enum ip_conntrack_info ctinfo;
int err;
#endif #endif
unsigned int ret; unsigned int ret;
@ -195,9 +196,11 @@ nf_nat_ipv4_out(unsigned int hooknum,
ct->tuplehash[!dir].tuple.dst.u3.ip) || ct->tuplehash[!dir].tuple.dst.u3.ip) ||
(ct->tuplehash[dir].tuple.dst.protonum != IPPROTO_ICMP && (ct->tuplehash[dir].tuple.dst.protonum != IPPROTO_ICMP &&
ct->tuplehash[dir].tuple.src.u.all != ct->tuplehash[dir].tuple.src.u.all !=
ct->tuplehash[!dir].tuple.dst.u.all)) ct->tuplehash[!dir].tuple.dst.u.all)) {
if (nf_xfrm_me_harder(skb, AF_INET) < 0) err = nf_xfrm_me_harder(skb, AF_INET);
ret = NF_DROP; if (err < 0)
ret = NF_DROP_ERR(err);
}
} }
#endif #endif
return ret; return ret;
@ -235,9 +238,11 @@ nf_nat_ipv4_local_fn(unsigned int hooknum,
else if (!(IPCB(skb)->flags & IPSKB_XFRM_TRANSFORMED) && else if (!(IPCB(skb)->flags & IPSKB_XFRM_TRANSFORMED) &&
ct->tuplehash[dir].tuple.dst.protonum != IPPROTO_ICMP && ct->tuplehash[dir].tuple.dst.protonum != IPPROTO_ICMP &&
ct->tuplehash[dir].tuple.dst.u.all != ct->tuplehash[dir].tuple.dst.u.all !=
ct->tuplehash[!dir].tuple.src.u.all) ct->tuplehash[!dir].tuple.src.u.all) {
if (nf_xfrm_me_harder(skb, AF_INET) < 0) err = nf_xfrm_me_harder(skb, AF_INET);
ret = NF_DROP; if (err < 0)
ret = NF_DROP_ERR(err);
}
#endif #endif
} }
return ret; return ret;

View File

@ -179,6 +179,7 @@ nf_nat_ipv6_out(unsigned int hooknum,
#ifdef CONFIG_XFRM #ifdef CONFIG_XFRM
const struct nf_conn *ct; const struct nf_conn *ct;
enum ip_conntrack_info ctinfo; enum ip_conntrack_info ctinfo;
int err;
#endif #endif
unsigned int ret; unsigned int ret;
@ -197,9 +198,11 @@ nf_nat_ipv6_out(unsigned int hooknum,
&ct->tuplehash[!dir].tuple.dst.u3) || &ct->tuplehash[!dir].tuple.dst.u3) ||
(ct->tuplehash[dir].tuple.dst.protonum != IPPROTO_ICMPV6 && (ct->tuplehash[dir].tuple.dst.protonum != IPPROTO_ICMPV6 &&
ct->tuplehash[dir].tuple.src.u.all != ct->tuplehash[dir].tuple.src.u.all !=
ct->tuplehash[!dir].tuple.dst.u.all)) ct->tuplehash[!dir].tuple.dst.u.all)) {
if (nf_xfrm_me_harder(skb, AF_INET6) < 0) err = nf_xfrm_me_harder(skb, AF_INET6);
ret = NF_DROP; if (err < 0)
ret = NF_DROP_ERR(err);
}
} }
#endif #endif
return ret; return ret;
@ -236,9 +239,11 @@ nf_nat_ipv6_local_fn(unsigned int hooknum,
else if (!(IP6CB(skb)->flags & IP6SKB_XFRM_TRANSFORMED) && else if (!(IP6CB(skb)->flags & IP6SKB_XFRM_TRANSFORMED) &&
ct->tuplehash[dir].tuple.dst.protonum != IPPROTO_ICMPV6 && ct->tuplehash[dir].tuple.dst.protonum != IPPROTO_ICMPV6 &&
ct->tuplehash[dir].tuple.dst.u.all != ct->tuplehash[dir].tuple.dst.u.all !=
ct->tuplehash[!dir].tuple.src.u.all) ct->tuplehash[!dir].tuple.src.u.all) {
if (nf_xfrm_me_harder(skb, AF_INET6)) err = nf_xfrm_me_harder(skb, AF_INET6);
ret = NF_DROP; if (err < 0)
ret = NF_DROP_ERR(err);
}
#endif #endif
} }
return ret; return ret;

View File

@ -87,9 +87,10 @@ int nf_xfrm_me_harder(struct sk_buff *skb, unsigned int family)
struct flowi fl; struct flowi fl;
unsigned int hh_len; unsigned int hh_len;
struct dst_entry *dst; struct dst_entry *dst;
int err;
if (xfrm_decode_session(skb, &fl, family) < 0) err = xfrm_decode_session(skb, &fl, family);
return -1; return err;
dst = skb_dst(skb); dst = skb_dst(skb);
if (dst->xfrm) if (dst->xfrm)
@ -98,7 +99,7 @@ int nf_xfrm_me_harder(struct sk_buff *skb, unsigned int family)
dst = xfrm_lookup(dev_net(dst->dev), dst, &fl, skb->sk, 0); dst = xfrm_lookup(dev_net(dst->dev), dst, &fl, skb->sk, 0);
if (IS_ERR(dst)) if (IS_ERR(dst))
return -1; return PTR_ERR(dst);
skb_dst_drop(skb); skb_dst_drop(skb);
skb_dst_set(skb, dst); skb_dst_set(skb, dst);
@ -107,7 +108,7 @@ int nf_xfrm_me_harder(struct sk_buff *skb, unsigned int family)
hh_len = skb_dst(skb)->dev->hard_header_len; hh_len = skb_dst(skb)->dev->hard_header_len;
if (skb_headroom(skb) < hh_len && if (skb_headroom(skb) < hh_len &&
pskb_expand_head(skb, hh_len - skb_headroom(skb), 0, GFP_ATOMIC)) pskb_expand_head(skb, hh_len - skb_headroom(skb), 0, GFP_ATOMIC))
return -1; return -ENOMEM;
return 0; return 0;
} }
EXPORT_SYMBOL(nf_xfrm_me_harder); EXPORT_SYMBOL(nf_xfrm_me_harder);