Skip to content

Commit

Permalink
[NETFILTER]: Redo policy lookups after NAT when neccessary
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Patrick McHardy authored and David S. Miller committed Jan 7, 2006
1 parent 4e8e9de commit 5c901da
Showing 4 changed files with 32 additions and 3 deletions.
1 change: 1 addition & 0 deletions include/net/xfrm.h
Original file line number Diff line number Diff line change
@@ -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);
5 changes: 5 additions & 0 deletions net/ipv4/ip_output.c
Original file line number Diff line number Diff line change
@@ -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);
27 changes: 25 additions & 2 deletions net/ipv4/netfilter/ip_nat_standalone.c
Original file line number Diff line number Diff line change
@@ -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;
2 changes: 1 addition & 1 deletion net/ipv4/xfrm4_output.c
Original file line number Diff line number Diff line change
@@ -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;

0 comments on commit 5c901da

Please sign in to comment.