[NETFILTER]: Add NAT support for nf_conntrack
Add NAT support for nf_conntrack. Joint work of Jozsef Kadlecsik, Yasuyuki Kozakai, Martin Josefsson and myself. Signed-off-by: Jozsef Kadlecsik <kadlec@blackhole.kfki.hu> Signed-off-by: Patrick McHardy <kaber@trash.net> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
committed by
David S. Miller
parent
d2483ddefd
commit
5b1158e909
@@ -579,7 +579,8 @@ __nf_conntrack_alloc(const struct nf_conntrack_tuple *orig,
|
||||
/* FIXME: protect helper list per RCU */
|
||||
read_lock_bh(&nf_conntrack_lock);
|
||||
helper = __nf_ct_helper_find(repl);
|
||||
if (helper)
|
||||
/* NAT might want to assign a helper later */
|
||||
if (helper || features & NF_CT_F_NAT)
|
||||
features |= NF_CT_F_HELP;
|
||||
read_unlock_bh(&nf_conntrack_lock);
|
||||
|
||||
@@ -850,6 +851,26 @@ int nf_ct_invert_tuplepr(struct nf_conntrack_tuple *inverse,
|
||||
orig->dst.protonum));
|
||||
}
|
||||
|
||||
/* Alter reply tuple (maybe alter helper). This is for NAT, and is
|
||||
implicitly racy: see __nf_conntrack_confirm */
|
||||
void nf_conntrack_alter_reply(struct nf_conn *ct,
|
||||
const struct nf_conntrack_tuple *newreply)
|
||||
{
|
||||
struct nf_conn_help *help = nfct_help(ct);
|
||||
|
||||
write_lock_bh(&nf_conntrack_lock);
|
||||
/* Should be unconfirmed, so not in hash table yet */
|
||||
NF_CT_ASSERT(!nf_ct_is_confirmed(ct));
|
||||
|
||||
DEBUGP("Altering reply tuple of %p to ", ct);
|
||||
NF_CT_DUMP_TUPLE(newreply);
|
||||
|
||||
ct->tuplehash[IP_CT_DIR_REPLY].tuple = *newreply;
|
||||
if (!ct->master && help && help->expecting == 0)
|
||||
help->helper = __nf_ct_helper_find(newreply);
|
||||
write_unlock_bh(&nf_conntrack_lock);
|
||||
}
|
||||
|
||||
/* Refresh conntrack for this many jiffies and do accounting if do_acct is 1 */
|
||||
void __nf_ct_refresh_acct(struct nf_conn *ct,
|
||||
enum ip_conntrack_info ctinfo,
|
||||
|
@@ -39,7 +39,11 @@
|
||||
#include <net/netfilter/nf_conntrack_helper.h>
|
||||
#include <net/netfilter/nf_conntrack_l3proto.h>
|
||||
#include <net/netfilter/nf_conntrack_l4proto.h>
|
||||
#include <linux/netfilter_ipv4/ip_nat_protocol.h>
|
||||
#include <net/netfilter/nf_conntrack_tuple.h>
|
||||
#ifdef CONFIG_NF_NAT_NEEDED
|
||||
#include <net/netfilter/nf_nat_core.h>
|
||||
#include <net/netfilter/nf_nat_protocol.h>
|
||||
#endif
|
||||
|
||||
#include <linux/netfilter/nfnetlink.h>
|
||||
#include <linux/netfilter/nfnetlink_conntrack.h>
|
||||
@@ -430,7 +434,7 @@ ctnetlink_dump_table(struct sk_buff *skb, struct netlink_callback *cb)
|
||||
restart:
|
||||
list_for_each_prev(i, &nf_conntrack_hash[cb->args[0]]) {
|
||||
h = (struct nf_conntrack_tuple_hash *) i;
|
||||
if (DIRECTION(h) != IP_CT_DIR_ORIGINAL)
|
||||
if (NF_CT_DIRECTION(h) != IP_CT_DIR_ORIGINAL)
|
||||
continue;
|
||||
ct = nf_ct_tuplehash_to_ctrack(h);
|
||||
/* Dump entries of a given L3 protocol number.
|
||||
@@ -556,28 +560,28 @@ ctnetlink_parse_tuple(struct nfattr *cda[], struct nf_conntrack_tuple *tuple,
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_IP_NF_NAT_NEEDED
|
||||
#ifdef CONFIG_NF_NAT_NEEDED
|
||||
static const size_t cta_min_protonat[CTA_PROTONAT_MAX] = {
|
||||
[CTA_PROTONAT_PORT_MIN-1] = sizeof(u_int16_t),
|
||||
[CTA_PROTONAT_PORT_MAX-1] = sizeof(u_int16_t),
|
||||
};
|
||||
|
||||
static int ctnetlink_parse_nat_proto(struct nfattr *attr,
|
||||
static int nfnetlink_parse_nat_proto(struct nfattr *attr,
|
||||
const struct nf_conn *ct,
|
||||
struct ip_nat_range *range)
|
||||
struct nf_nat_range *range)
|
||||
{
|
||||
struct nfattr *tb[CTA_PROTONAT_MAX];
|
||||
struct ip_nat_protocol *npt;
|
||||
struct nf_nat_protocol *npt;
|
||||
|
||||
nfattr_parse_nested(tb, CTA_PROTONAT_MAX, attr);
|
||||
|
||||
if (nfattr_bad_size(tb, CTA_PROTONAT_MAX, cta_min_protonat))
|
||||
return -EINVAL;
|
||||
|
||||
npt = ip_nat_proto_find_get(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum);
|
||||
npt = nf_nat_proto_find_get(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum);
|
||||
|
||||
if (!npt->nfattr_to_range) {
|
||||
ip_nat_proto_put(npt);
|
||||
nf_nat_proto_put(npt);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -585,7 +589,7 @@ static int ctnetlink_parse_nat_proto(struct nfattr *attr,
|
||||
if (npt->nfattr_to_range(tb, range) > 0)
|
||||
range->flags |= IP_NAT_RANGE_PROTO_SPECIFIED;
|
||||
|
||||
ip_nat_proto_put(npt);
|
||||
nf_nat_proto_put(npt);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -596,8 +600,8 @@ static const size_t cta_min_nat[CTA_NAT_MAX] = {
|
||||
};
|
||||
|
||||
static inline int
|
||||
ctnetlink_parse_nat(struct nfattr *nat,
|
||||
const struct nf_conn *ct, struct ip_nat_range *range)
|
||||
nfnetlink_parse_nat(struct nfattr *nat,
|
||||
const struct nf_conn *ct, struct nf_nat_range *range)
|
||||
{
|
||||
struct nfattr *tb[CTA_NAT_MAX];
|
||||
int err;
|
||||
@@ -623,7 +627,7 @@ ctnetlink_parse_nat(struct nfattr *nat,
|
||||
if (!tb[CTA_NAT_PROTO-1])
|
||||
return 0;
|
||||
|
||||
err = ctnetlink_parse_nat_proto(tb[CTA_NAT_PROTO-1], ct, range);
|
||||
err = nfnetlink_parse_nat_proto(tb[CTA_NAT_PROTO-1], ct, range);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
@@ -798,35 +802,35 @@ ctnetlink_change_status(struct nf_conn *ct, struct nfattr *cda[])
|
||||
return -EINVAL;
|
||||
|
||||
if (cda[CTA_NAT_SRC-1] || cda[CTA_NAT_DST-1]) {
|
||||
#ifndef CONFIG_IP_NF_NAT_NEEDED
|
||||
#ifndef CONFIG_NF_NAT_NEEDED
|
||||
return -EINVAL;
|
||||
#else
|
||||
struct ip_nat_range range;
|
||||
struct nf_nat_range range;
|
||||
|
||||
if (cda[CTA_NAT_DST-1]) {
|
||||
if (ctnetlink_parse_nat(cda[CTA_NAT_DST-1], ct,
|
||||
if (nfnetlink_parse_nat(cda[CTA_NAT_DST-1], ct,
|
||||
&range) < 0)
|
||||
return -EINVAL;
|
||||
if (ip_nat_initialized(ct,
|
||||
if (nf_nat_initialized(ct,
|
||||
HOOK2MANIP(NF_IP_PRE_ROUTING)))
|
||||
return -EEXIST;
|
||||
ip_nat_setup_info(ct, &range, hooknum);
|
||||
nf_nat_setup_info(ct, &range, NF_IP_PRE_ROUTING);
|
||||
}
|
||||
if (cda[CTA_NAT_SRC-1]) {
|
||||
if (ctnetlink_parse_nat(cda[CTA_NAT_SRC-1], ct,
|
||||
if (nfnetlink_parse_nat(cda[CTA_NAT_SRC-1], ct,
|
||||
&range) < 0)
|
||||
return -EINVAL;
|
||||
if (ip_nat_initialized(ct,
|
||||
if (nf_nat_initialized(ct,
|
||||
HOOK2MANIP(NF_IP_POST_ROUTING)))
|
||||
return -EEXIST;
|
||||
ip_nat_setup_info(ct, &range, hooknum);
|
||||
nf_nat_setup_info(ct, &range, NF_IP_POST_ROUTING);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Be careful here, modifying NAT bits can screw up things,
|
||||
* so don't let users modify them directly if they don't pass
|
||||
* ip_nat_range. */
|
||||
* nf_nat_range. */
|
||||
ct->status |= status & ~(IPS_NAT_DONE_MASK | IPS_NAT_MASK);
|
||||
return 0;
|
||||
}
|
||||
|
@@ -730,7 +730,7 @@ static int tcp_in_window(struct ip_ct_tcp *state,
|
||||
return res;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_IP_NF_NAT_NEEDED
|
||||
#ifdef CONFIG_NF_NAT_NEEDED
|
||||
/* Update sender->td_end after NAT successfully mangled the packet */
|
||||
/* Caller must linearize skb at tcp header. */
|
||||
void nf_conntrack_tcp_update(struct sk_buff *skb,
|
||||
|
@@ -530,8 +530,11 @@ EXPORT_SYMBOL(nf_conntrack_lock);
|
||||
EXPORT_SYMBOL(nf_conntrack_hash);
|
||||
EXPORT_SYMBOL(nf_conntrack_untracked);
|
||||
EXPORT_SYMBOL_GPL(nf_conntrack_find_get);
|
||||
#ifdef CONFIG_IP_NF_NAT_NEEDED
|
||||
#ifdef CONFIG_NF_NAT_NEEDED
|
||||
EXPORT_SYMBOL(nf_conntrack_tcp_update);
|
||||
EXPORT_SYMBOL(nf_conntrack_register_cache);
|
||||
EXPORT_SYMBOL(nf_conntrack_unregister_cache);
|
||||
EXPORT_SYMBOL(nf_conntrack_alter_reply);
|
||||
#endif
|
||||
EXPORT_SYMBOL(__nf_conntrack_confirm);
|
||||
EXPORT_SYMBOL(nf_ct_get_tuple);
|
||||
|
Reference in New Issue
Block a user