[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>
This commit is contained in:
parent
b59c270104
commit
eb9c7ebe69
|
@ -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;
|
||||||
#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)
|
||||||
|
|
||||||
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)
|
||||||
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)
|
||||||
}
|
}
|
||||||
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 @@
|
||||||
: ((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)
|
||||||
|
|
||||||
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)
|
||||||
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 @@
|
||||||
#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,
|
||||||
|
|
||||||
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);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue