Skip to content

Commit

Permalink
[NETFILTER]: Handle NAT in IPsec policy checks
Browse files Browse the repository at this point in the history
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 <[email protected]>
Signed-off-by: David S. Miller <[email protected]>
  • Loading branch information
kaber authored and David S. Miller committed Jan 7, 2006
1 parent b59c270 commit eb9c7eb
Show file tree
Hide file tree
Showing 5 changed files with 70 additions and 3 deletions.
16 changes: 16 additions & 0 deletions include/linux/netfilter.h
Original file line number Diff line number Diff line change
Expand Up @@ -274,6 +274,20 @@ struct nf_queue_rerouter {
extern int nf_register_queue_rerouter(int pf, struct nf_queue_rerouter *rer);
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
#include <linux/proc_fs.h>
extern struct proc_dir_entry *proc_net_netfilter;
Expand All @@ -282,6 +296,8 @@ extern struct proc_dir_entry *proc_net_netfilter;
#else /* !CONFIG_NETFILTER */
#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_nat_decode_session(struct sk_buff *skb, struct flowi *fl, int family) {}
#endif /*CONFIG_NETFILTER*/

#endif /*__KERNEL__*/
Expand Down
2 changes: 1 addition & 1 deletion net/dccp/ipv4.c
Original file line number Diff line number Diff line change
Expand Up @@ -986,6 +986,7 @@ int dccp_v4_rcv(struct sk_buff *skb)

if (!xfrm4_policy_check(sk, XFRM_POLICY_IN, skb))
goto discard_and_relse;
nf_reset(skb);

return sk_receive_skb(sk, skb);

Expand Down Expand Up @@ -1099,7 +1100,6 @@ int dccp_v4_destroy_sock(struct sock *sk)
kfree_skb(sk->sk_send_head);
sk->sk_send_head = NULL;
}
nf_reset(skb);

/* Clean up a referenced DCCP bind bucket. */
if (inet_csk(sk)->icsk_bind_hash != NULL)
Expand Down
3 changes: 3 additions & 0 deletions net/ipv4/netfilter.c
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,9 @@ int ip_route_me_harder(struct sk_buff **pskb)
}
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
* returns control to the table.
Expand Down
50 changes: 48 additions & 2 deletions net/ipv4/netfilter/ip_nat_standalone.c
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,44 @@
: ((hooknum) == NF_IP_LOCAL_IN ? "LOCAL_IN" \
: "*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
ip_nat_fn(unsigned int hooknum,
struct sk_buff **pskb,
Expand Down Expand Up @@ -330,10 +368,14 @@ static int init_or_cleanup(int init)

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();
if (ret < 0) {
printk("ip_nat_init: can't setup rules.\n");
goto cleanup_nothing;
goto cleanup_decode_session;
}
ret = nf_register_hook(&ip_nat_in_ops);
if (ret < 0) {
Expand Down Expand Up @@ -381,7 +423,11 @@ static int init_or_cleanup(int init)
nf_unregister_hook(&ip_nat_in_ops);
cleanup_rule_init:
ip_nat_rule_cleanup();
cleanup_nothing:
cleanup_decode_session:
#ifdef CONFIG_XFRM
ip_nat_decode_session = NULL;
synchronize_net();
#endif
return ret;
}

Expand Down
2 changes: 2 additions & 0 deletions net/xfrm/xfrm_policy.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
#include <linux/workqueue.h>
#include <linux/notifier.h>
#include <linux/netdevice.h>
#include <linux/netfilter.h>
#include <linux/module.h>
#include <net/xfrm.h>
#include <net/ip.h>
Expand Down Expand Up @@ -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)
return 0;
nf_nat_decode_session(skb, &fl, family);

sk_sid = security_sk_sid(sk, &fl, fl_dir);

Expand Down

0 comments on commit eb9c7eb

Please sign in to comment.