diff options
author | Patrick McHardy <kaber@trash.net> | 2006-01-07 02:06:30 -0500 |
---|---|---|
committer | David S. Miller <davem@sunset.davemloft.net> | 2006-01-07 15:57:37 -0500 |
commit | eb9c7ebe6980c41cf6ae889e301c3b49f473ee9f (patch) | |
tree | 419103d15b9de9c26c8400c698625231df55da91 | |
parent | b59c270104f03960069596722fea70340579244d (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.h | 16 | ||||
-rw-r--r-- | net/dccp/ipv4.c | 2 | ||||
-rw-r--r-- | net/ipv4/netfilter.c | 3 | ||||
-rw-r--r-- | net/ipv4/netfilter/ip_nat_standalone.c | 50 | ||||
-rw-r--r-- | net/xfrm/xfrm_policy.c | 2 |
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 { | |||
274 | extern int nf_register_queue_rerouter(int pf, struct nf_queue_rerouter *rer); | 274 | extern int nf_register_queue_rerouter(int pf, struct nf_queue_rerouter *rer); |
275 | extern int nf_unregister_queue_rerouter(int pf); | 275 | extern int nf_unregister_queue_rerouter(int pf); |
276 | 276 | ||
277 | #include <net/flow.h> | ||
278 | extern void (*ip_nat_decode_session)(struct sk_buff *, struct flowi *); | ||
279 | |||
280 | static inline void | ||
281 | nf_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> |
279 | extern struct proc_dir_entry *proc_net_netfilter; | 293 | extern 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) |
284 | static inline void nf_ct_attach(struct sk_buff *new, struct sk_buff *skb) {} | 298 | static inline void nf_ct_attach(struct sk_buff *new, struct sk_buff *skb) {} |
299 | static inline void | ||
300 | nf_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 | } |
87 | EXPORT_SYMBOL(ip_route_me_harder); | 87 | EXPORT_SYMBOL(ip_route_me_harder); |
88 | 88 | ||
89 | void (*ip_nat_decode_session)(struct sk_buff *, struct flowi *); | ||
90 | EXPORT_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 | ||
59 | static 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 | |||
58 | static unsigned int | 96 | static unsigned int |
59 | ip_nat_fn(unsigned int hooknum, | 97 | ip_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 | ||