Commit eb9c7ebe authored by Patrick McHardy's avatar Patrick McHardy Committed by David S. Miller

[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: default avatarPatrick McHardy <kaber@trash.net>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent b59c2701
...@@ -274,6 +274,20 @@ struct nf_queue_rerouter { ...@@ -274,6 +274,20 @@ struct nf_queue_rerouter {
extern int nf_register_queue_rerouter(int pf, struct nf_queue_rerouter *rer); extern int nf_register_queue_rerouter(int pf, struct nf_queue_rerouter *rer);
extern int nf_unregister_queue_rerouter(int pf); extern int nf_unregister_queue_rerouter(int pf);
#include <net/flow.h>
extern void (*ip_nat_decode_session)(struct sk_buff *, struct flowi *);
static inline void
nf_nat_decode_session(struct sk_buff *skb, struct flowi *fl, int family)
{
#ifdef CONFIG_IP_NF_NAT_NEEDED
void (*decodefn)(struct sk_buff *, struct flowi *);
if (family == AF_INET && (decodefn = ip_nat_decode_session) != NULL)
decodefn(skb, fl);
#endif
}
#ifdef CONFIG_PROC_FS #ifdef CONFIG_PROC_FS
#include <linux/proc_fs.h> #include <linux/proc_fs.h>
extern struct proc_dir_entry *proc_net_netfilter; extern struct proc_dir_entry *proc_net_netfilter;
...@@ -282,6 +296,8 @@ extern struct proc_dir_entry *proc_net_netfilter; ...@@ -282,6 +296,8 @@ extern struct proc_dir_entry *proc_net_netfilter;
#else /* !CONFIG_NETFILTER */ #else /* !CONFIG_NETFILTER */
#define NF_HOOK(pf, hook, skb, indev, outdev, okfn) (okfn)(skb) #define NF_HOOK(pf, hook, skb, indev, outdev, okfn) (okfn)(skb)
static inline void nf_ct_attach(struct sk_buff *new, struct sk_buff *skb) {} static inline void nf_ct_attach(struct sk_buff *new, struct sk_buff *skb) {}
static inline void
nf_nat_decode_session(struct sk_buff *skb, struct flowi *fl, int family) {}
#endif /*CONFIG_NETFILTER*/ #endif /*CONFIG_NETFILTER*/
#endif /*__KERNEL__*/ #endif /*__KERNEL__*/
......
...@@ -986,6 +986,7 @@ int dccp_v4_rcv(struct sk_buff *skb) ...@@ -986,6 +986,7 @@ int dccp_v4_rcv(struct sk_buff *skb)
if (!xfrm4_policy_check(sk, XFRM_POLICY_IN, skb)) if (!xfrm4_policy_check(sk, XFRM_POLICY_IN, skb))
goto discard_and_relse; goto discard_and_relse;
nf_reset(skb);
return sk_receive_skb(sk, skb); return sk_receive_skb(sk, skb);
...@@ -1099,7 +1100,6 @@ int dccp_v4_destroy_sock(struct sock *sk) ...@@ -1099,7 +1100,6 @@ int dccp_v4_destroy_sock(struct sock *sk)
kfree_skb(sk->sk_send_head); kfree_skb(sk->sk_send_head);
sk->sk_send_head = NULL; sk->sk_send_head = NULL;
} }
nf_reset(skb);
/* Clean up a referenced DCCP bind bucket. */ /* Clean up a referenced DCCP bind bucket. */
if (inet_csk(sk)->icsk_bind_hash != NULL) if (inet_csk(sk)->icsk_bind_hash != NULL)
......
...@@ -86,6 +86,9 @@ int ip_route_me_harder(struct sk_buff **pskb) ...@@ -86,6 +86,9 @@ int ip_route_me_harder(struct sk_buff **pskb)
} }
EXPORT_SYMBOL(ip_route_me_harder); EXPORT_SYMBOL(ip_route_me_harder);
void (*ip_nat_decode_session)(struct sk_buff *, struct flowi *);
EXPORT_SYMBOL(ip_nat_decode_session);
/* /*
* Extra routing may needed on local out, as the QUEUE target never * Extra routing may needed on local out, as the QUEUE target never
* returns control to the table. * returns control to the table.
......
...@@ -55,6 +55,44 @@ ...@@ -55,6 +55,44 @@
: ((hooknum) == NF_IP_LOCAL_IN ? "LOCAL_IN" \ : ((hooknum) == NF_IP_LOCAL_IN ? "LOCAL_IN" \
: "*ERROR*"))) : "*ERROR*")))
#ifdef CONFIG_XFRM
static void nat_decode_session(struct sk_buff *skb, struct flowi *fl)
{
struct ip_conntrack *ct;
struct ip_conntrack_tuple *t;
enum ip_conntrack_info ctinfo;
enum ip_conntrack_dir dir;
unsigned long statusbit;
ct = ip_conntrack_get(skb, &ctinfo);
if (ct == NULL)
return;
dir = CTINFO2DIR(ctinfo);
t = &ct->tuplehash[dir].tuple;
if (dir == IP_CT_DIR_ORIGINAL)
statusbit = IPS_DST_NAT;
else
statusbit = IPS_SRC_NAT;
if (ct->status & statusbit) {
fl->fl4_dst = t->dst.ip;
if (t->dst.protonum == IPPROTO_TCP ||
t->dst.protonum == IPPROTO_UDP)
fl->fl_ip_dport = t->dst.u.tcp.port;
}
statusbit ^= IPS_NAT_MASK;
if (ct->status & statusbit) {
fl->fl4_src = t->src.ip;
if (t->dst.protonum == IPPROTO_TCP ||
t->dst.protonum == IPPROTO_UDP)
fl->fl_ip_sport = t->src.u.tcp.port;
}
}
#endif
static unsigned int static unsigned int
ip_nat_fn(unsigned int hooknum, ip_nat_fn(unsigned int hooknum,
struct sk_buff **pskb, struct sk_buff **pskb,
...@@ -330,10 +368,14 @@ static int init_or_cleanup(int init) ...@@ -330,10 +368,14 @@ static int init_or_cleanup(int init)
if (!init) goto cleanup; if (!init) goto cleanup;
#ifdef CONFIG_XFRM
BUG_ON(ip_nat_decode_session != NULL);
ip_nat_decode_session = nat_decode_session;
#endif
ret = ip_nat_rule_init(); ret = ip_nat_rule_init();
if (ret < 0) { if (ret < 0) {
printk("ip_nat_init: can't setup rules.\n"); printk("ip_nat_init: can't setup rules.\n");
goto cleanup_nothing; goto cleanup_decode_session;
} }
ret = nf_register_hook(&ip_nat_in_ops); ret = nf_register_hook(&ip_nat_in_ops);
if (ret < 0) { if (ret < 0) {
...@@ -381,7 +423,11 @@ static int init_or_cleanup(int init) ...@@ -381,7 +423,11 @@ static int init_or_cleanup(int init)
nf_unregister_hook(&ip_nat_in_ops); nf_unregister_hook(&ip_nat_in_ops);
cleanup_rule_init: cleanup_rule_init:
ip_nat_rule_cleanup(); ip_nat_rule_cleanup();
cleanup_nothing: cleanup_decode_session:
#ifdef CONFIG_XFRM
ip_nat_decode_session = NULL;
synchronize_net();
#endif
return ret; return ret;
} }
......
...@@ -22,6 +22,7 @@ ...@@ -22,6 +22,7 @@
#include <linux/workqueue.h> #include <linux/workqueue.h>
#include <linux/notifier.h> #include <linux/notifier.h>
#include <linux/netdevice.h> #include <linux/netdevice.h>
#include <linux/netfilter.h>
#include <linux/module.h> #include <linux/module.h>
#include <net/xfrm.h> #include <net/xfrm.h>
#include <net/ip.h> #include <net/ip.h>
...@@ -985,6 +986,7 @@ int __xfrm_policy_check(struct sock *sk, int dir, struct sk_buff *skb, ...@@ -985,6 +986,7 @@ int __xfrm_policy_check(struct sock *sk, int dir, struct sk_buff *skb,
if (xfrm_decode_session(skb, &fl, family) < 0) if (xfrm_decode_session(skb, &fl, family) < 0)
return 0; return 0;
nf_nat_decode_session(skb, &fl, family);
sk_sid = security_sk_sid(sk, &fl, fl_dir); sk_sid = security_sk_sid(sk, &fl, fl_dir);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment