Skip to content

Commit

Permalink
[NETFILTER]: nf_nat: kill helper and seq_adjust hooks
Browse files Browse the repository at this point in the history
Connection tracking helpers (specifically FTP) need to be called
before NAT sequence numbers adjustments are performed to be able
to compare them against previously seen ones. We've introduced
two new hooks around 2.6.11 to maintain this ordering when NAT
modules were changed to get called from conntrack helpers directly.

The cost of netfilter hooks is quite high and sequence number
adjustments are only rarely needed however. Add a RCU-protected
sequence number adjustment function pointer and call it from
IPv4 conntrack after calling the helper.

Signed-off-by: Patrick McHardy <kaber@trash.net>
  • Loading branch information
Patrick McHardy committed Apr 14, 2008
1 parent 55871d0 commit dd13b01
Show file tree
Hide file tree
Showing 6 changed files with 35 additions and 67 deletions.
2 changes: 0 additions & 2 deletions include/linux/netfilter_ipv4.h
Original file line number Diff line number Diff line change
Expand Up @@ -62,8 +62,6 @@ enum nf_ip_hook_priorities {
NF_IP_PRI_FILTER = 0,
NF_IP_PRI_NAT_SRC = 100,
NF_IP_PRI_SELINUX_LAST = 225,
NF_IP_PRI_CONNTRACK_HELPER = INT_MAX - 2,
NF_IP_PRI_NAT_SEQ_ADJUST = INT_MAX - 1,
NF_IP_PRI_CONNTRACK_CONFIRM = INT_MAX,
NF_IP_PRI_LAST = INT_MAX,
};
Expand Down
3 changes: 3 additions & 0 deletions include/net/netfilter/nf_nat_helper.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ extern int nf_nat_mangle_udp_packet(struct sk_buff *skb,
extern int nf_nat_seq_adjust(struct sk_buff *skb,
struct nf_conn *ct,
enum ip_conntrack_info ctinfo);
extern int (*nf_nat_seq_adjust_hook)(struct sk_buff *skb,
struct nf_conn *ct,
enum ip_conntrack_info ctinfo);

/* Setup NAT on this expected conntrack so it follows master, but goes
* to port ct->master->saved_proto. */
Expand Down
56 changes: 27 additions & 29 deletions net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,12 @@
#include <net/netfilter/nf_conntrack_l3proto.h>
#include <net/netfilter/nf_conntrack_core.h>
#include <net/netfilter/ipv4/nf_conntrack_ipv4.h>
#include <net/netfilter/nf_nat_helper.h>

int (*nf_nat_seq_adjust_hook)(struct sk_buff *skb,
struct nf_conn *ct,
enum ip_conntrack_info ctinfo);
EXPORT_SYMBOL_GPL(nf_nat_seq_adjust_hook);

static int ipv4_pkt_to_tuple(const struct sk_buff *skb, unsigned int nhoff,
struct nf_conntrack_tuple *tuple)
Expand Down Expand Up @@ -100,36 +106,42 @@ static unsigned int ipv4_confirm(unsigned int hooknum,
const struct net_device *in,
const struct net_device *out,
int (*okfn)(struct sk_buff *))
{
/* We've seen it coming out the other side: confirm it */
return nf_conntrack_confirm(skb);
}

static unsigned int ipv4_conntrack_help(unsigned int hooknum,
struct sk_buff *skb,
const struct net_device *in,
const struct net_device *out,
int (*okfn)(struct sk_buff *))
{
struct nf_conn *ct;
enum ip_conntrack_info ctinfo;
const struct nf_conn_help *help;
const struct nf_conntrack_helper *helper;
unsigned int ret;

/* This is where we call the helper: as the packet goes out. */
ct = nf_ct_get(skb, &ctinfo);
if (!ct || ctinfo == IP_CT_RELATED + IP_CT_IS_REPLY)
return NF_ACCEPT;
goto out;

help = nfct_help(ct);
if (!help)
return NF_ACCEPT;
goto out;

/* rcu_read_lock()ed by nf_hook_slow */
helper = rcu_dereference(help->helper);
if (!helper)
return NF_ACCEPT;
return helper->help(skb, skb_network_offset(skb) + ip_hdrlen(skb),
ct, ctinfo);
goto out;

ret = helper->help(skb, skb_network_offset(skb) + ip_hdrlen(skb),
ct, ctinfo);
if (ret != NF_ACCEPT)
return ret;

if (test_bit(IPS_SEQ_ADJUST_BIT, &ct->status)) {
typeof(nf_nat_seq_adjust_hook) seq_adjust;

seq_adjust = rcu_dereference(nf_nat_seq_adjust_hook);
if (!seq_adjust || !seq_adjust(skb, ct, ctinfo))
return NF_DROP;
}
out:
/* We've seen it coming out the other side: confirm it */
return nf_conntrack_confirm(skb);
}

static unsigned int ipv4_conntrack_defrag(unsigned int hooknum,
Expand Down Expand Up @@ -210,20 +222,6 @@ static struct nf_hook_ops ipv4_conntrack_ops[] __read_mostly = {
.hooknum = NF_INET_LOCAL_OUT,
.priority = NF_IP_PRI_CONNTRACK,
},
{
.hook = ipv4_conntrack_help,
.owner = THIS_MODULE,
.pf = PF_INET,
.hooknum = NF_INET_POST_ROUTING,
.priority = NF_IP_PRI_CONNTRACK_HELPER,
},
{
.hook = ipv4_conntrack_help,
.owner = THIS_MODULE,
.pf = PF_INET,
.hooknum = NF_INET_LOCAL_IN,
.priority = NF_IP_PRI_CONNTRACK_HELPER,
},
{
.hook = ipv4_confirm,
.owner = THIS_MODULE,
Expand Down
5 changes: 5 additions & 0 deletions net/ipv4/netfilter/nf_nat_core.c
Original file line number Diff line number Diff line change
Expand Up @@ -618,6 +618,9 @@ static int __init nf_nat_init(void)
nf_conntrack_untracked.status |= IPS_NAT_DONE_MASK;

l3proto = nf_ct_l3proto_find_get((u_int16_t)AF_INET);

BUG_ON(nf_nat_seq_adjust_hook != NULL);
rcu_assign_pointer(nf_nat_seq_adjust_hook, nf_nat_seq_adjust);
return 0;

cleanup_extend:
Expand All @@ -644,6 +647,8 @@ static void __exit nf_nat_cleanup(void)
nf_ct_free_hashtable(bysource, nf_nat_vmalloced, nf_nat_htable_size);
nf_ct_l3proto_put(l3proto);
nf_ct_extend_unregister(&nat_extend);
rcu_assign_pointer(nf_nat_seq_adjust_hook, NULL);
synchronize_net();
}

MODULE_LICENSE("GPL");
Expand Down
1 change: 0 additions & 1 deletion net/ipv4/netfilter/nf_nat_helper.c
Original file line number Diff line number Diff line change
Expand Up @@ -416,7 +416,6 @@ nf_nat_seq_adjust(struct sk_buff *skb,

return 1;
}
EXPORT_SYMBOL(nf_nat_seq_adjust);

/* Setup NAT on this expected conntrack so it follows master. */
/* If we fail to get a free NAT slot, we'll get dropped on confirm */
Expand Down
35 changes: 0 additions & 35 deletions net/ipv4/netfilter/nf_nat_standalone.c
Original file line number Diff line number Diff line change
Expand Up @@ -245,25 +245,6 @@ nf_nat_local_fn(unsigned int hooknum,
return ret;
}

static unsigned int
nf_nat_adjust(unsigned int hooknum,
struct sk_buff *skb,
const struct net_device *in,
const struct net_device *out,
int (*okfn)(struct sk_buff *))
{
struct nf_conn *ct;
enum ip_conntrack_info ctinfo;

ct = nf_ct_get(skb, &ctinfo);
if (ct && test_bit(IPS_SEQ_ADJUST_BIT, &ct->status)) {
pr_debug("nf_nat_standalone: adjusting sequence number\n");
if (!nf_nat_seq_adjust(skb, ct, ctinfo))
return NF_DROP;
}
return NF_ACCEPT;
}

/* We must be after connection tracking and before packet filtering. */

static struct nf_hook_ops nf_nat_ops[] __read_mostly = {
Expand All @@ -283,14 +264,6 @@ static struct nf_hook_ops nf_nat_ops[] __read_mostly = {
.hooknum = NF_INET_POST_ROUTING,
.priority = NF_IP_PRI_NAT_SRC,
},
/* After conntrack, adjust sequence number */
{
.hook = nf_nat_adjust,
.owner = THIS_MODULE,
.pf = PF_INET,
.hooknum = NF_INET_POST_ROUTING,
.priority = NF_IP_PRI_NAT_SEQ_ADJUST,
},
/* Before packet filtering, change destination */
{
.hook = nf_nat_local_fn,
Expand All @@ -307,14 +280,6 @@ static struct nf_hook_ops nf_nat_ops[] __read_mostly = {
.hooknum = NF_INET_LOCAL_IN,
.priority = NF_IP_PRI_NAT_SRC,
},
/* After conntrack, adjust sequence number */
{
.hook = nf_nat_adjust,
.owner = THIS_MODULE,
.pf = PF_INET,
.hooknum = NF_INET_LOCAL_IN,
.priority = NF_IP_PRI_NAT_SEQ_ADJUST,
},
};

static int __init nf_nat_standalone_init(void)
Expand Down

0 comments on commit dd13b01

Please sign in to comment.