Skip to content

Commit 5c901da

Browse files
kaberDavid S. Miller
authored andcommitted
[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>
1 parent 4e8e9de commit 5c901da

File tree

4 files changed

+32
-3
lines changed

4 files changed

+32
-3
lines changed

include/net/xfrm.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -866,6 +866,7 @@ extern int xfrm_state_mtu(struct xfrm_state *x, int mtu);
866866
extern int xfrm_init_state(struct xfrm_state *x);
867867
extern int xfrm4_rcv(struct sk_buff *skb);
868868
extern int xfrm4_output(struct sk_buff *skb);
869+
extern int xfrm4_output_finish(struct sk_buff *skb);
869870
extern int xfrm4_tunnel_register(struct xfrm_tunnel *handler);
870871
extern int xfrm4_tunnel_deregister(struct xfrm_tunnel *handler);
871872
extern int xfrm6_rcv_spi(struct sk_buff **pskb, u32 spi);

net/ipv4/ip_output.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,11 @@ static inline int ip_finish_output2(struct sk_buff *skb)
202202

203203
static inline int ip_finish_output(struct sk_buff *skb)
204204
{
205+
#if defined(CONFIG_NETFILTER) && defined(CONFIG_XFRM)
206+
/* Policy lookup after SNAT yielded a new policy */
207+
if (skb->dst->xfrm != NULL)
208+
return xfrm4_output_finish(skb);
209+
#endif
205210
if (skb->len > dst_mtu(skb->dst) &&
206211
!(skb_shinfo(skb)->ufo_size || skb_shinfo(skb)->tso_size))
207212
return ip_fragment(skb, ip_finish_output2);

net/ipv4/netfilter/ip_nat_standalone.c

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -187,12 +187,30 @@ ip_nat_out(unsigned int hooknum,
187187
const struct net_device *out,
188188
int (*okfn)(struct sk_buff *))
189189
{
190+
struct ip_conntrack *ct;
191+
enum ip_conntrack_info ctinfo;
192+
unsigned int ret;
193+
190194
/* root is playing with raw sockets. */
191195
if ((*pskb)->len < sizeof(struct iphdr)
192196
|| (*pskb)->nh.iph->ihl * 4 < sizeof(struct iphdr))
193197
return NF_ACCEPT;
194198

195-
return ip_nat_fn(hooknum, pskb, in, out, okfn);
199+
ret = ip_nat_fn(hooknum, pskb, in, out, okfn);
200+
if (ret != NF_DROP && ret != NF_STOLEN
201+
&& (ct = ip_conntrack_get(*pskb, &ctinfo)) != NULL) {
202+
enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
203+
204+
if (ct->tuplehash[dir].tuple.src.ip !=
205+
ct->tuplehash[!dir].tuple.dst.ip
206+
#ifdef CONFIG_XFRM
207+
|| ct->tuplehash[dir].tuple.src.u.all !=
208+
ct->tuplehash[!dir].tuple.dst.u.all
209+
#endif
210+
)
211+
return ip_route_me_harder(pskb) == 0 ? ret : NF_DROP;
212+
}
213+
return ret;
196214
}
197215

198216
static unsigned int
@@ -217,7 +235,12 @@ ip_nat_local_fn(unsigned int hooknum,
217235
enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
218236

219237
if (ct->tuplehash[dir].tuple.dst.ip !=
220-
ct->tuplehash[!dir].tuple.src.ip)
238+
ct->tuplehash[!dir].tuple.src.ip
239+
#ifdef CONFIG_XFRM
240+
|| ct->tuplehash[dir].tuple.dst.u.all !=
241+
ct->tuplehash[dir].tuple.src.u.all
242+
#endif
243+
)
221244
return ip_route_me_harder(pskb) == 0 ? ret : NF_DROP;
222245
}
223246
return ret;

net/ipv4/xfrm4_output.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -152,7 +152,7 @@ static int xfrm4_output_one(struct sk_buff *skb)
152152
goto out_exit;
153153
}
154154

155-
static int xfrm4_output_finish(struct sk_buff *skb)
155+
int xfrm4_output_finish(struct sk_buff *skb)
156156
{
157157
int err;
158158

0 commit comments

Comments
 (0)