aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPatrick McHardy <kaber@trash.net>2006-01-07 02:05:36 -0500
committerDavid S. Miller <davem@sunset.davemloft.net>2006-01-07 15:57:35 -0500
commit5c901daaea3be0d900b3ae1fc9b5f64ff94e4f02 (patch)
tree7532b280d892bab7fd9af98b02a3f81929ddca5d
parent4e8e9de7c25315669e2d5565acc50ec379522c28 (diff)
[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>
-rw-r--r--include/net/xfrm.h1
-rw-r--r--net/ipv4/ip_output.c5
-rw-r--r--net/ipv4/netfilter/ip_nat_standalone.c27
-rw-r--r--net/ipv4/xfrm4_output.c2
4 files changed, 32 insertions, 3 deletions
diff --git a/include/net/xfrm.h b/include/net/xfrm.h
index d6111a2f0a23..d09ca0e7d139 100644
--- a/include/net/xfrm.h
+++ b/include/net/xfrm.h
@@ -866,6 +866,7 @@ extern int xfrm_state_mtu(struct xfrm_state *x, int mtu);
866extern int xfrm_init_state(struct xfrm_state *x); 866extern int xfrm_init_state(struct xfrm_state *x);
867extern int xfrm4_rcv(struct sk_buff *skb); 867extern int xfrm4_rcv(struct sk_buff *skb);
868extern int xfrm4_output(struct sk_buff *skb); 868extern int xfrm4_output(struct sk_buff *skb);
869extern int xfrm4_output_finish(struct sk_buff *skb);
869extern int xfrm4_tunnel_register(struct xfrm_tunnel *handler); 870extern int xfrm4_tunnel_register(struct xfrm_tunnel *handler);
870extern int xfrm4_tunnel_deregister(struct xfrm_tunnel *handler); 871extern int xfrm4_tunnel_deregister(struct xfrm_tunnel *handler);
871extern int xfrm6_rcv_spi(struct sk_buff **pskb, u32 spi); 872extern int xfrm6_rcv_spi(struct sk_buff **pskb, u32 spi);
diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c
index 8b1c9bd0091e..59fdac3a099a 100644
--- a/net/ipv4/ip_output.c
+++ b/net/ipv4/ip_output.c
@@ -202,6 +202,11 @@ static inline int ip_finish_output2(struct sk_buff *skb)
202 202
203static inline int ip_finish_output(struct sk_buff *skb) 203static inline int ip_finish_output(struct sk_buff *skb)
204{ 204{
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
205 if (skb->len > dst_mtu(skb->dst) && 210 if (skb->len > dst_mtu(skb->dst) &&
206 !(skb_shinfo(skb)->ufo_size || skb_shinfo(skb)->tso_size)) 211 !(skb_shinfo(skb)->ufo_size || skb_shinfo(skb)->tso_size))
207 return ip_fragment(skb, ip_finish_output2); 212 return ip_fragment(skb, ip_finish_output2);
diff --git a/net/ipv4/netfilter/ip_nat_standalone.c b/net/ipv4/netfilter/ip_nat_standalone.c
index 1bb50897a5a2..b518697af4db 100644
--- a/net/ipv4/netfilter/ip_nat_standalone.c
+++ b/net/ipv4/netfilter/ip_nat_standalone.c
@@ -187,12 +187,30 @@ ip_nat_out(unsigned int hooknum,
187 const struct net_device *out, 187 const struct net_device *out,
188 int (*okfn)(struct sk_buff *)) 188 int (*okfn)(struct sk_buff *))
189{ 189{
190 struct ip_conntrack *ct;
191 enum ip_conntrack_info ctinfo;
192 unsigned int ret;
193
190 /* root is playing with raw sockets. */ 194 /* root is playing with raw sockets. */
191 if ((*pskb)->len < sizeof(struct iphdr) 195 if ((*pskb)->len < sizeof(struct iphdr)
192 || (*pskb)->nh.iph->ihl * 4 < sizeof(struct iphdr)) 196 || (*pskb)->nh.iph->ihl * 4 < sizeof(struct iphdr))
193 return NF_ACCEPT; 197 return NF_ACCEPT;
194 198
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;
196} 214}
197 215
198static unsigned int 216static unsigned int
@@ -217,7 +235,12 @@ ip_nat_local_fn(unsigned int hooknum,
217 enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); 235 enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
218 236
219 if (ct->tuplehash[dir].tuple.dst.ip != 237 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 )
221 return ip_route_me_harder(pskb) == 0 ? ret : NF_DROP; 244 return ip_route_me_harder(pskb) == 0 ? ret : NF_DROP;
222 } 245 }
223 return ret; 246 return ret;
diff --git a/net/ipv4/xfrm4_output.c b/net/ipv4/xfrm4_output.c
index 160c48800ab8..d4df0ddd424b 100644
--- a/net/ipv4/xfrm4_output.c
+++ b/net/ipv4/xfrm4_output.c
@@ -152,7 +152,7 @@ error_nolock:
152 goto out_exit; 152 goto out_exit;
153} 153}
154 154
155static int xfrm4_output_finish(struct sk_buff *skb) 155int xfrm4_output_finish(struct sk_buff *skb)
156{ 156{
157 int err; 157 int err;
158 158