[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:
committed by
David S. Miller
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 xfrm_init_state(struct xfrm_state *x);
|
||||||
extern int xfrm4_rcv(struct sk_buff *skb);
|
extern int xfrm4_rcv(struct sk_buff *skb);
|
||||||
extern int xfrm4_output(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_register(struct xfrm_tunnel *handler);
|
||||||
extern int xfrm4_tunnel_deregister(struct xfrm_tunnel *handler);
|
extern int xfrm4_tunnel_deregister(struct xfrm_tunnel *handler);
|
||||||
extern int xfrm6_rcv_spi(struct sk_buff **pskb, u32 spi);
|
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)
|
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) &&
|
if (skb->len > dst_mtu(skb->dst) &&
|
||||||
!(skb_shinfo(skb)->ufo_size || skb_shinfo(skb)->tso_size))
|
!(skb_shinfo(skb)->ufo_size || skb_shinfo(skb)->tso_size))
|
||||||
return ip_fragment(skb, ip_finish_output2);
|
return ip_fragment(skb, ip_finish_output2);
|
||||||
|
@@ -187,12 +187,30 @@ ip_nat_out(unsigned int hooknum,
|
|||||||
const struct net_device *out,
|
const struct net_device *out,
|
||||||
int (*okfn)(struct sk_buff *))
|
int (*okfn)(struct sk_buff *))
|
||||||
{
|
{
|
||||||
|
struct ip_conntrack *ct;
|
||||||
|
enum ip_conntrack_info ctinfo;
|
||||||
|
unsigned int ret;
|
||||||
|
|
||||||
/* root is playing with raw sockets. */
|
/* root is playing with raw sockets. */
|
||||||
if ((*pskb)->len < sizeof(struct iphdr)
|
if ((*pskb)->len < sizeof(struct iphdr)
|
||||||
|| (*pskb)->nh.iph->ihl * 4 < sizeof(struct iphdr))
|
|| (*pskb)->nh.iph->ihl * 4 < sizeof(struct iphdr))
|
||||||
return NF_ACCEPT;
|
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
|
static unsigned int
|
||||||
@@ -217,7 +235,12 @@ ip_nat_local_fn(unsigned int hooknum,
|
|||||||
enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
|
enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
|
||||||
|
|
||||||
if (ct->tuplehash[dir].tuple.dst.ip !=
|
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 ip_route_me_harder(pskb) == 0 ? ret : NF_DROP;
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
|
@@ -152,7 +152,7 @@ error_nolock:
|
|||||||
goto out_exit;
|
goto out_exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int xfrm4_output_finish(struct sk_buff *skb)
|
int xfrm4_output_finish(struct sk_buff *skb)
|
||||||
{
|
{
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user