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
Show file tree
Hide file tree
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
Expand Up @@ -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);
Expand Down
5 changes: 5 additions & 0 deletions net/ipv4/ip_output.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
27 changes: 25 additions & 2 deletions net/ipv4/netfilter/ip_nat_standalone.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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;
Expand Down
2 changes: 1 addition & 1 deletion net/ipv4/xfrm4_output.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down

0 comments on commit 5c901da

Please sign in to comment.