forked from luck/tmp_suning_uos_patched
[NETFILTER]: Redo policy lookups after NAT when neccessary
When NAT changes the key used for the xfrm lookup it needs to be done again. If a new policy is returned in POST_ROUTING the packet needs to be passed to xfrm4_output_one manually after all hooks were called because POST_ROUTING is called with fixed okfn (ip_finish_output). Signed-off-by: Patrick McHardy <kaber@trash.net> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
4e8e9de7c2
commit
5c901daaea
|
@ -866,6 +866,7 @@ extern int xfrm_state_mtu(struct xfrm_state *x, int mtu);
|
|||
extern int xfrm_init_state(struct xfrm_state *x);
|
||||
extern int xfrm4_rcv(struct sk_buff *skb);
|
||||
extern int xfrm4_output(struct sk_buff *skb);
|
||||
extern int xfrm4_output_finish(struct sk_buff *skb);
|
||||
extern int xfrm4_tunnel_register(struct xfrm_tunnel *handler);
|
||||
extern int xfrm4_tunnel_deregister(struct xfrm_tunnel *handler);
|
||||
extern int xfrm6_rcv_spi(struct sk_buff **pskb, u32 spi);
|
||||
|
|
|
@ -202,6 +202,11 @@ static inline int ip_finish_output2(struct sk_buff *skb)
|
|||
|
||||
static inline int ip_finish_output(struct sk_buff *skb)
|
||||
{
|
||||
#if defined(CONFIG_NETFILTER) && defined(CONFIG_XFRM)
|
||||
/* Policy lookup after SNAT yielded a new policy */
|
||||
if (skb->dst->xfrm != NULL)
|
||||
return xfrm4_output_finish(skb);
|
||||
#endif
|
||||
if (skb->len > dst_mtu(skb->dst) &&
|
||||
!(skb_shinfo(skb)->ufo_size || skb_shinfo(skb)->tso_size))
|
||||
return ip_fragment(skb, ip_finish_output2);
|
||||
|
|
|
@ -187,12 +187,30 @@ ip_nat_out(unsigned int hooknum,
|
|||
const struct net_device *out,
|
||||
int (*okfn)(struct sk_buff *))
|
||||
{
|
||||
struct ip_conntrack *ct;
|
||||
enum ip_conntrack_info ctinfo;
|
||||
unsigned int ret;
|
||||
|
||||
/* root is playing with raw sockets. */
|
||||
if ((*pskb)->len < sizeof(struct iphdr)
|
||||
|| (*pskb)->nh.iph->ihl * 4 < sizeof(struct iphdr))
|
||||
return NF_ACCEPT;
|
||||
|
||||
return ip_nat_fn(hooknum, pskb, in, out, okfn);
|
||||
ret = ip_nat_fn(hooknum, pskb, in, out, okfn);
|
||||
if (ret != NF_DROP && ret != NF_STOLEN
|
||||
&& (ct = ip_conntrack_get(*pskb, &ctinfo)) != NULL) {
|
||||
enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
|
||||
|
||||
if (ct->tuplehash[dir].tuple.src.ip !=
|
||||
ct->tuplehash[!dir].tuple.dst.ip
|
||||
#ifdef CONFIG_XFRM
|
||||
|| ct->tuplehash[dir].tuple.src.u.all !=
|
||||
ct->tuplehash[!dir].tuple.dst.u.all
|
||||
#endif
|
||||
)
|
||||
return ip_route_me_harder(pskb) == 0 ? ret : NF_DROP;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static unsigned int
|
||||
|
@ -217,7 +235,12 @@ ip_nat_local_fn(unsigned int hooknum,
|
|||
enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
|
||||
|
||||
if (ct->tuplehash[dir].tuple.dst.ip !=
|
||||
ct->tuplehash[!dir].tuple.src.ip)
|
||||
ct->tuplehash[!dir].tuple.src.ip
|
||||
#ifdef CONFIG_XFRM
|
||||
|| ct->tuplehash[dir].tuple.dst.u.all !=
|
||||
ct->tuplehash[dir].tuple.src.u.all
|
||||
#endif
|
||||
)
|
||||
return ip_route_me_harder(pskb) == 0 ? ret : NF_DROP;
|
||||
}
|
||||
return ret;
|
||||
|
|
|
@ -152,7 +152,7 @@ static int xfrm4_output_one(struct sk_buff *skb)
|
|||
goto out_exit;
|
||||
}
|
||||
|
||||
static int xfrm4_output_finish(struct sk_buff *skb)
|
||||
int xfrm4_output_finish(struct sk_buff *skb)
|
||||
{
|
||||
int err;
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user