aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPatrick McHardy <kaber@trash.net>2006-01-07 02:06:30 -0500
committerDavid S. Miller <davem@sunset.davemloft.net>2006-01-07 15:57:37 -0500
commiteb9c7ebe6980c41cf6ae889e301c3b49f473ee9f (patch)
tree419103d15b9de9c26c8400c698625231df55da91
parentb59c270104f03960069596722fea70340579244d (diff)
[NETFILTER]: Handle NAT in IPsec policy checks
Handle NAT of decapsulated IPsec packets by reconstructing the struct flowi of the original packet from the conntrack information for IPsec policy checks. Signed-off-by: Patrick McHardy <kaber@trash.net> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--include/linux/netfilter.h16
-rw-r--r--net/dccp/ipv4.c2
-rw-r--r--net/ipv4/netfilter.c3
-rw-r--r--net/ipv4/netfilter/ip_nat_standalone.c50
-rw-r--r--net/xfrm/xfrm_policy.c2
5 files changed, 70 insertions, 3 deletions
diff --git a/include/linux/netfilter.h b/include/linux/netfilter.h
index 79bb977afeac..84506dfa1f37 100644
--- a/include/linux/netfilter.h
+++ b/include/linux/netfilter.h
@@ -274,6 +274,20 @@ struct nf_queue_rerouter {
274extern int nf_register_queue_rerouter(int pf, struct nf_queue_rerouter *rer); 274extern int nf_register_queue_rerouter(int pf, struct nf_queue_rerouter *rer);
275extern int nf_unregister_queue_rerouter(int pf); 275extern int nf_unregister_queue_rerouter(int pf);
276 276
277#include <net/flow.h>
278extern void (*ip_nat_decode_session)(struct sk_buff *, struct flowi *);
279
280static inline void
281nf_nat_decode_session(struct sk_buff *skb, struct flowi *fl, int family)
282{
283#ifdef CONFIG_IP_NF_NAT_NEEDED
284 void (*decodefn)(struct sk_buff *, struct flowi *);
285
286 if (family == AF_INET && (decodefn = ip_nat_decode_session) != NULL)
287 decodefn(skb, fl);
288#endif
289}
290
277#ifdef CONFIG_PROC_FS 291#ifdef CONFIG_PROC_FS
278#include <linux/proc_fs.h> 292#include <linux/proc_fs.h>
279extern struct proc_dir_entry *proc_net_netfilter; 293extern struct proc_dir_entry *proc_net_netfilter;
@@ -282,6 +296,8 @@ extern struct proc_dir_entry *proc_net_netfilter;
282#else /* !CONFIG_NETFILTER */ 296#else /* !CONFIG_NETFILTER */
283#define NF_HOOK(pf, hook, skb, indev, outdev, okfn) (okfn)(skb) 297#define NF_HOOK(pf, hook, skb, indev, outdev, okfn) (okfn)(skb)
284static inline void nf_ct_attach(struct sk_buff *new, struct sk_buff *skb) {} 298static inline void nf_ct_attach(struct sk_buff *new, struct sk_buff *skb) {}
299static inline void
300nf_nat_decode_session(struct sk_buff *skb, struct flowi *fl, int family) {}
285#endif /*CONFIG_NETFILTER*/ 301#endif /*CONFIG_NETFILTER*/
286 302
287#endif /*__KERNEL__*/ 303#endif /*__KERNEL__*/
diff --git a/net/dccp/ipv4.c b/net/dccp/ipv4.c
index 23ba177c1150..00f983226672 100644
--- a/net/dccp/ipv4.c
+++ b/net/dccp/ipv4.c
@@ -986,6 +986,7 @@ int dccp_v4_rcv(struct sk_buff *skb)
986 986
987 if (!xfrm4_policy_check(sk, XFRM_POLICY_IN, skb)) 987 if (!xfrm4_policy_check(sk, XFRM_POLICY_IN, skb))
988 goto discard_and_relse; 988 goto discard_and_relse;
989 nf_reset(skb);
989 990
990 return sk_receive_skb(sk, skb); 991 return sk_receive_skb(sk, skb);
991 992
@@ -1099,7 +1100,6 @@ int dccp_v4_destroy_sock(struct sock *sk)
1099 kfree_skb(sk->sk_send_head); 1100 kfree_skb(sk->sk_send_head);
1100 sk->sk_send_head = NULL; 1101 sk->sk_send_head = NULL;
1101 } 1102 }
1102 nf_reset(skb);
1103 1103
1104 /* Clean up a referenced DCCP bind bucket. */ 1104 /* Clean up a referenced DCCP bind bucket. */
1105 if (inet_csk(sk)->icsk_bind_hash != NULL) 1105 if (inet_csk(sk)->icsk_bind_hash != NULL)
diff --git a/net/ipv4/netfilter.c b/net/ipv4/netfilter.c
index 4c637a1cbd23..3321092b0914 100644
--- a/net/ipv4/netfilter.c
+++ b/net/ipv4/netfilter.c
@@ -86,6 +86,9 @@ int ip_route_me_harder(struct sk_buff **pskb)
86} 86}
87EXPORT_SYMBOL(ip_route_me_harder); 87EXPORT_SYMBOL(ip_route_me_harder);
88 88
89void (*ip_nat_decode_session)(struct sk_buff *, struct flowi *);
90EXPORT_SYMBOL(ip_nat_decode_session);
91
89/* 92/*
90 * Extra routing may needed on local out, as the QUEUE target never 93 * Extra routing may needed on local out, as the QUEUE target never
91 * returns control to the table. 94 * returns control to the table.
diff --git a/net/ipv4/netfilter/ip_nat_standalone.c b/net/ipv4/netfilter/ip_nat_standalone.c
index b518697af4db..8b8a1f00bbf4 100644
--- a/net/ipv4/netfilter/ip_nat_standalone.c
+++ b/net/ipv4/netfilter/ip_nat_standalone.c
@@ -55,6 +55,44 @@
55 : ((hooknum) == NF_IP_LOCAL_IN ? "LOCAL_IN" \ 55 : ((hooknum) == NF_IP_LOCAL_IN ? "LOCAL_IN" \
56 : "*ERROR*"))) 56 : "*ERROR*")))
57 57
58#ifdef CONFIG_XFRM
59static void nat_decode_session(struct sk_buff *skb, struct flowi *fl)
60{
61 struct ip_conntrack *ct;
62 struct ip_conntrack_tuple *t;
63 enum ip_conntrack_info ctinfo;
64 enum ip_conntrack_dir dir;
65 unsigned long statusbit;
66
67 ct = ip_conntrack_get(skb, &ctinfo);
68 if (ct == NULL)
69 return;
70 dir = CTINFO2DIR(ctinfo);
71 t = &ct->tuplehash[dir].tuple;
72
73 if (dir == IP_CT_DIR_ORIGINAL)
74 statusbit = IPS_DST_NAT;
75 else
76 statusbit = IPS_SRC_NAT;
77
78 if (ct->status & statusbit) {
79 fl->fl4_dst = t->dst.ip;
80 if (t->dst.protonum == IPPROTO_TCP ||
81 t->dst.protonum == IPPROTO_UDP)
82 fl->fl_ip_dport = t->dst.u.tcp.port;
83 }
84
85 statusbit ^= IPS_NAT_MASK;
86
87 if (ct->status & statusbit) {
88 fl->fl4_src = t->src.ip;
89 if (t->dst.protonum == IPPROTO_TCP ||
90 t->dst.protonum == IPPROTO_UDP)
91 fl->fl_ip_sport = t->src.u.tcp.port;
92 }
93}
94#endif
95
58static unsigned int 96static unsigned int
59ip_nat_fn(unsigned int hooknum, 97ip_nat_fn(unsigned int hooknum,
60 struct sk_buff **pskb, 98 struct sk_buff **pskb,
@@ -330,10 +368,14 @@ static int init_or_cleanup(int init)
330 368
331 if (!init) goto cleanup; 369 if (!init) goto cleanup;
332 370
371#ifdef CONFIG_XFRM
372 BUG_ON(ip_nat_decode_session != NULL);
373 ip_nat_decode_session = nat_decode_session;
374#endif
333 ret = ip_nat_rule_init(); 375 ret = ip_nat_rule_init();
334 if (ret < 0) { 376 if (ret < 0) {
335 printk("ip_nat_init: can't setup rules.\n"); 377 printk("ip_nat_init: can't setup rules.\n");
336 goto cleanup_nothing; 378 goto cleanup_decode_session;
337 } 379 }
338 ret = nf_register_hook(&ip_nat_in_ops); 380 ret = nf_register_hook(&ip_nat_in_ops);
339 if (ret < 0) { 381 if (ret < 0) {
@@ -381,7 +423,11 @@ static int init_or_cleanup(int init)
381 nf_unregister_hook(&ip_nat_in_ops); 423 nf_unregister_hook(&ip_nat_in_ops);
382 cleanup_rule_init: 424 cleanup_rule_init:
383 ip_nat_rule_cleanup(); 425 ip_nat_rule_cleanup();
384 cleanup_nothing: 426 cleanup_decode_session:
427#ifdef CONFIG_XFRM
428 ip_nat_decode_session = NULL;
429 synchronize_net();
430#endif
385 return ret; 431 return ret;
386} 432}
387 433
diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c
index f2edc9225b6a..59614a994b4e 100644
--- a/net/xfrm/xfrm_policy.c
+++ b/net/xfrm/xfrm_policy.c
@@ -22,6 +22,7 @@
22#include <linux/workqueue.h> 22#include <linux/workqueue.h>
23#include <linux/notifier.h> 23#include <linux/notifier.h>
24#include <linux/netdevice.h> 24#include <linux/netdevice.h>
25#include <linux/netfilter.h>
25#include <linux/module.h> 26#include <linux/module.h>
26#include <net/xfrm.h> 27#include <net/xfrm.h>
27#include <net/ip.h> 28#include <net/ip.h>
@@ -985,6 +986,7 @@ int __xfrm_policy_check(struct sock *sk, int dir, struct sk_buff *skb,
985 986
986 if (xfrm_decode_session(skb, &fl, family) < 0) 987 if (xfrm_decode_session(skb, &fl, family) < 0)
987 return 0; 988 return 0;
989 nf_nat_decode_session(skb, &fl, family);
988 990
989 sk_sid = security_sk_sid(sk, &fl, fl_dir); 991 sk_sid = security_sk_sid(sk, &fl, fl_dir);
990 992