Merge branch 'master' of git://1984.lsi.us.es/nf-next
Pablo Neira Ayuso says: ==================== The following patchset contain updates for your net-next tree, they are: * Fix (for just added) connlabel dependencies, from Florian Westphal. * Add aliasing support for conntrack, thus users can either use -m state or -m conntrack from iptables while using the same kernel module, from Jozsef Kadlecsik. * Some code refactoring for the CT target to merge common code in revision 0 and 1, from myself. * Add aliasing support for CT, based on patch from Jozsef Kadlecsik. * Add one mutex per nfnetlink subsystem, from myself. * Improved logging for packets that are dropped by helpers, from myself. ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
commit
2ccba5433b
|
@ -34,8 +34,8 @@ extern int nfnetlink_send(struct sk_buff *skb, struct net *net, u32 pid, unsigne
|
||||||
extern int nfnetlink_set_err(struct net *net, u32 pid, u32 group, int error);
|
extern int nfnetlink_set_err(struct net *net, u32 pid, u32 group, int error);
|
||||||
extern int nfnetlink_unicast(struct sk_buff *skb, struct net *net, u_int32_t pid, int flags);
|
extern int nfnetlink_unicast(struct sk_buff *skb, struct net *net, u_int32_t pid, int flags);
|
||||||
|
|
||||||
extern void nfnl_lock(void);
|
extern void nfnl_lock(__u8 subsys_id);
|
||||||
extern void nfnl_unlock(void);
|
extern void nfnl_unlock(__u8 subsys_id);
|
||||||
|
|
||||||
#define MODULE_ALIAS_NFNL_SUBSYS(subsys) \
|
#define MODULE_ALIAS_NFNL_SUBSYS(subsys) \
|
||||||
MODULE_ALIAS("nfnetlink-subsys-" __stringify(subsys))
|
MODULE_ALIAS("nfnetlink-subsys-" __stringify(subsys))
|
||||||
|
|
|
@ -100,6 +100,10 @@ struct nf_ct_helper_expectfn {
|
||||||
void (*expectfn)(struct nf_conn *ct, struct nf_conntrack_expect *exp);
|
void (*expectfn)(struct nf_conn *ct, struct nf_conntrack_expect *exp);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
__printf(3,4)
|
||||||
|
void nf_ct_helper_log(struct sk_buff *skb, const struct nf_conn *ct,
|
||||||
|
const char *fmt, ...);
|
||||||
|
|
||||||
void nf_ct_helper_expectfn_register(struct nf_ct_helper_expectfn *n);
|
void nf_ct_helper_expectfn_register(struct nf_ct_helper_expectfn *n);
|
||||||
void nf_ct_helper_expectfn_unregister(struct nf_ct_helper_expectfn *n);
|
void nf_ct_helper_expectfn_unregister(struct nf_ct_helper_expectfn *n);
|
||||||
struct nf_ct_helper_expectfn *
|
struct nf_ct_helper_expectfn *
|
||||||
|
|
|
@ -3,7 +3,11 @@
|
||||||
|
|
||||||
#include <linux/types.h>
|
#include <linux/types.h>
|
||||||
|
|
||||||
#define XT_CT_NOTRACK 0x1
|
enum {
|
||||||
|
XT_CT_NOTRACK = 1 << 0,
|
||||||
|
XT_CT_NOTRACK_ALIAS = 1 << 1,
|
||||||
|
XT_CT_MASK = XT_CT_NOTRACK | XT_CT_NOTRACK_ALIAS,
|
||||||
|
};
|
||||||
|
|
||||||
struct xt_ct_target_info {
|
struct xt_ct_target_info {
|
||||||
__u16 flags;
|
__u16 flags;
|
||||||
|
|
|
@ -31,6 +31,7 @@ enum {
|
||||||
XT_CONNTRACK_REPLSRC_PORT = 1 << 10,
|
XT_CONNTRACK_REPLSRC_PORT = 1 << 10,
|
||||||
XT_CONNTRACK_REPLDST_PORT = 1 << 11,
|
XT_CONNTRACK_REPLDST_PORT = 1 << 11,
|
||||||
XT_CONNTRACK_DIRECTION = 1 << 12,
|
XT_CONNTRACK_DIRECTION = 1 << 12,
|
||||||
|
XT_CONNTRACK_STATE_ALIAS = 1 << 13,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct xt_conntrack_mtinfo1 {
|
struct xt_conntrack_mtinfo1 {
|
||||||
|
|
|
@ -100,7 +100,6 @@ static unsigned int ipv4_helper(unsigned int hooknum,
|
||||||
enum ip_conntrack_info ctinfo;
|
enum ip_conntrack_info ctinfo;
|
||||||
const struct nf_conn_help *help;
|
const struct nf_conn_help *help;
|
||||||
const struct nf_conntrack_helper *helper;
|
const struct nf_conntrack_helper *helper;
|
||||||
unsigned int ret;
|
|
||||||
|
|
||||||
/* This is where we call the helper: as the packet goes out. */
|
/* This is where we call the helper: as the packet goes out. */
|
||||||
ct = nf_ct_get(skb, &ctinfo);
|
ct = nf_ct_get(skb, &ctinfo);
|
||||||
|
@ -116,13 +115,8 @@ static unsigned int ipv4_helper(unsigned int hooknum,
|
||||||
if (!helper)
|
if (!helper)
|
||||||
return NF_ACCEPT;
|
return NF_ACCEPT;
|
||||||
|
|
||||||
ret = helper->help(skb, skb_network_offset(skb) + ip_hdrlen(skb),
|
return helper->help(skb, skb_network_offset(skb) + ip_hdrlen(skb),
|
||||||
ct, ctinfo);
|
ct, ctinfo);
|
||||||
if (ret != NF_ACCEPT && (ret & NF_VERDICT_MASK) != NF_QUEUE) {
|
|
||||||
nf_log_packet(NFPROTO_IPV4, hooknum, skb, in, out, NULL,
|
|
||||||
"nf_ct_%s: dropping packet", helper->name);
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static unsigned int ipv4_confirm(unsigned int hooknum,
|
static unsigned int ipv4_confirm(unsigned int hooknum,
|
||||||
|
|
|
@ -104,7 +104,6 @@ static unsigned int ipv6_helper(unsigned int hooknum,
|
||||||
const struct nf_conn_help *help;
|
const struct nf_conn_help *help;
|
||||||
const struct nf_conntrack_helper *helper;
|
const struct nf_conntrack_helper *helper;
|
||||||
enum ip_conntrack_info ctinfo;
|
enum ip_conntrack_info ctinfo;
|
||||||
unsigned int ret;
|
|
||||||
__be16 frag_off;
|
__be16 frag_off;
|
||||||
int protoff;
|
int protoff;
|
||||||
u8 nexthdr;
|
u8 nexthdr;
|
||||||
|
@ -130,12 +129,7 @@ static unsigned int ipv6_helper(unsigned int hooknum,
|
||||||
return NF_ACCEPT;
|
return NF_ACCEPT;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = helper->help(skb, protoff, ct, ctinfo);
|
return helper->help(skb, protoff, ct, ctinfo);
|
||||||
if (ret != NF_ACCEPT && (ret & NF_VERDICT_MASK) != NF_QUEUE) {
|
|
||||||
nf_log_packet(NFPROTO_IPV6, hooknum, skb, in, out, NULL,
|
|
||||||
"nf_ct_%s: dropping packet", helper->name);
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static unsigned int ipv6_confirm(unsigned int hooknum,
|
static unsigned int ipv6_confirm(unsigned int hooknum,
|
||||||
|
|
|
@ -860,6 +860,7 @@ config NETFILTER_XT_MATCH_CONNBYTES
|
||||||
config NETFILTER_XT_MATCH_CONNLABEL
|
config NETFILTER_XT_MATCH_CONNLABEL
|
||||||
tristate '"connlabel" match support'
|
tristate '"connlabel" match support'
|
||||||
select NF_CONNTRACK_LABELS
|
select NF_CONNTRACK_LABELS
|
||||||
|
depends on NF_CONNTRACK
|
||||||
depends on NETFILTER_ADVANCED
|
depends on NETFILTER_ADVANCED
|
||||||
---help---
|
---help---
|
||||||
This match allows you to test and assign userspace-defined labels names
|
This match allows you to test and assign userspace-defined labels names
|
||||||
|
|
|
@ -88,14 +88,14 @@ find_set_type(const char *name, u8 family, u8 revision)
|
||||||
static bool
|
static bool
|
||||||
load_settype(const char *name)
|
load_settype(const char *name)
|
||||||
{
|
{
|
||||||
nfnl_unlock();
|
nfnl_unlock(NFNL_SUBSYS_IPSET);
|
||||||
pr_debug("try to load ip_set_%s\n", name);
|
pr_debug("try to load ip_set_%s\n", name);
|
||||||
if (request_module("ip_set_%s", name) < 0) {
|
if (request_module("ip_set_%s", name) < 0) {
|
||||||
pr_warning("Can't find ip_set type %s\n", name);
|
pr_warning("Can't find ip_set type %s\n", name);
|
||||||
nfnl_lock();
|
nfnl_lock(NFNL_SUBSYS_IPSET);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
nfnl_lock();
|
nfnl_lock(NFNL_SUBSYS_IPSET);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -532,7 +532,7 @@ ip_set_nfnl_get(const char *name)
|
||||||
ip_set_id_t i, index = IPSET_INVALID_ID;
|
ip_set_id_t i, index = IPSET_INVALID_ID;
|
||||||
struct ip_set *s;
|
struct ip_set *s;
|
||||||
|
|
||||||
nfnl_lock();
|
nfnl_lock(NFNL_SUBSYS_IPSET);
|
||||||
for (i = 0; i < ip_set_max; i++) {
|
for (i = 0; i < ip_set_max; i++) {
|
||||||
s = nfnl_set(i);
|
s = nfnl_set(i);
|
||||||
if (s != NULL && STREQ(s->name, name)) {
|
if (s != NULL && STREQ(s->name, name)) {
|
||||||
|
@ -541,7 +541,7 @@ ip_set_nfnl_get(const char *name)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
nfnl_unlock();
|
nfnl_unlock(NFNL_SUBSYS_IPSET);
|
||||||
|
|
||||||
return index;
|
return index;
|
||||||
}
|
}
|
||||||
|
@ -561,13 +561,13 @@ ip_set_nfnl_get_byindex(ip_set_id_t index)
|
||||||
if (index > ip_set_max)
|
if (index > ip_set_max)
|
||||||
return IPSET_INVALID_ID;
|
return IPSET_INVALID_ID;
|
||||||
|
|
||||||
nfnl_lock();
|
nfnl_lock(NFNL_SUBSYS_IPSET);
|
||||||
set = nfnl_set(index);
|
set = nfnl_set(index);
|
||||||
if (set)
|
if (set)
|
||||||
__ip_set_get(set);
|
__ip_set_get(set);
|
||||||
else
|
else
|
||||||
index = IPSET_INVALID_ID;
|
index = IPSET_INVALID_ID;
|
||||||
nfnl_unlock();
|
nfnl_unlock(NFNL_SUBSYS_IPSET);
|
||||||
|
|
||||||
return index;
|
return index;
|
||||||
}
|
}
|
||||||
|
@ -584,11 +584,11 @@ void
|
||||||
ip_set_nfnl_put(ip_set_id_t index)
|
ip_set_nfnl_put(ip_set_id_t index)
|
||||||
{
|
{
|
||||||
struct ip_set *set;
|
struct ip_set *set;
|
||||||
nfnl_lock();
|
nfnl_lock(NFNL_SUBSYS_IPSET);
|
||||||
set = nfnl_set(index);
|
set = nfnl_set(index);
|
||||||
if (set != NULL)
|
if (set != NULL)
|
||||||
__ip_set_put(set);
|
__ip_set_put(set);
|
||||||
nfnl_unlock();
|
nfnl_unlock(NFNL_SUBSYS_IPSET);
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(ip_set_nfnl_put);
|
EXPORT_SYMBOL_GPL(ip_set_nfnl_put);
|
||||||
|
|
||||||
|
@ -1763,10 +1763,10 @@ ip_set_sockfn_get(struct sock *sk, int optval, void __user *user, int *len)
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
req_get->set.name[IPSET_MAXNAMELEN - 1] = '\0';
|
req_get->set.name[IPSET_MAXNAMELEN - 1] = '\0';
|
||||||
nfnl_lock();
|
nfnl_lock(NFNL_SUBSYS_IPSET);
|
||||||
find_set_and_id(req_get->set.name, &id);
|
find_set_and_id(req_get->set.name, &id);
|
||||||
req_get->set.index = id;
|
req_get->set.index = id;
|
||||||
nfnl_unlock();
|
nfnl_unlock(NFNL_SUBSYS_IPSET);
|
||||||
goto copy;
|
goto copy;
|
||||||
}
|
}
|
||||||
case IP_SET_OP_GET_BYINDEX: {
|
case IP_SET_OP_GET_BYINDEX: {
|
||||||
|
@ -1778,11 +1778,11 @@ ip_set_sockfn_get(struct sock *sk, int optval, void __user *user, int *len)
|
||||||
ret = -EINVAL;
|
ret = -EINVAL;
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
nfnl_lock();
|
nfnl_lock(NFNL_SUBSYS_IPSET);
|
||||||
set = nfnl_set(req_get->set.index);
|
set = nfnl_set(req_get->set.index);
|
||||||
strncpy(req_get->set.name, set ? set->name : "",
|
strncpy(req_get->set.name, set ? set->name : "",
|
||||||
IPSET_MAXNAMELEN);
|
IPSET_MAXNAMELEN);
|
||||||
nfnl_unlock();
|
nfnl_unlock(NFNL_SUBSYS_IPSET);
|
||||||
goto copy;
|
goto copy;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
|
|
|
@ -145,6 +145,7 @@ static int amanda_help(struct sk_buff *skb,
|
||||||
|
|
||||||
exp = nf_ct_expect_alloc(ct);
|
exp = nf_ct_expect_alloc(ct);
|
||||||
if (exp == NULL) {
|
if (exp == NULL) {
|
||||||
|
nf_ct_helper_log(skb, ct, "cannot alloc expectation");
|
||||||
ret = NF_DROP;
|
ret = NF_DROP;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
@ -158,8 +159,10 @@ static int amanda_help(struct sk_buff *skb,
|
||||||
if (nf_nat_amanda && ct->status & IPS_NAT_MASK)
|
if (nf_nat_amanda && ct->status & IPS_NAT_MASK)
|
||||||
ret = nf_nat_amanda(skb, ctinfo, protoff,
|
ret = nf_nat_amanda(skb, ctinfo, protoff,
|
||||||
off - dataoff, len, exp);
|
off - dataoff, len, exp);
|
||||||
else if (nf_ct_expect_related(exp) != 0)
|
else if (nf_ct_expect_related(exp) != 0) {
|
||||||
|
nf_ct_helper_log(skb, ct, "cannot add expectation");
|
||||||
ret = NF_DROP;
|
ret = NF_DROP;
|
||||||
|
}
|
||||||
nf_ct_expect_put(exp);
|
nf_ct_expect_put(exp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -435,8 +435,8 @@ skip_nl_seq:
|
||||||
connection tracking, not packet filtering.
|
connection tracking, not packet filtering.
|
||||||
However, it is necessary for accurate tracking in
|
However, it is necessary for accurate tracking in
|
||||||
this case. */
|
this case. */
|
||||||
pr_debug("conntrack_ftp: partial %s %u+%u\n",
|
nf_ct_helper_log(skb, ct, "partial matching of `%s'",
|
||||||
search[dir][i].pattern, ntohl(th->seq), datalen);
|
search[dir][i].pattern);
|
||||||
ret = NF_DROP;
|
ret = NF_DROP;
|
||||||
goto out;
|
goto out;
|
||||||
} else if (found == 0) { /* No match */
|
} else if (found == 0) { /* No match */
|
||||||
|
@ -450,6 +450,7 @@ skip_nl_seq:
|
||||||
|
|
||||||
exp = nf_ct_expect_alloc(ct);
|
exp = nf_ct_expect_alloc(ct);
|
||||||
if (exp == NULL) {
|
if (exp == NULL) {
|
||||||
|
nf_ct_helper_log(skb, ct, "cannot alloc expectation");
|
||||||
ret = NF_DROP;
|
ret = NF_DROP;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
@ -500,9 +501,10 @@ skip_nl_seq:
|
||||||
protoff, matchoff, matchlen, exp);
|
protoff, matchoff, matchlen, exp);
|
||||||
else {
|
else {
|
||||||
/* Can't expect this? Best to drop packet now. */
|
/* Can't expect this? Best to drop packet now. */
|
||||||
if (nf_ct_expect_related(exp) != 0)
|
if (nf_ct_expect_related(exp) != 0) {
|
||||||
|
nf_ct_helper_log(skb, ct, "cannot add expectation");
|
||||||
ret = NF_DROP;
|
ret = NF_DROP;
|
||||||
else
|
} else
|
||||||
ret = NF_ACCEPT;
|
ret = NF_ACCEPT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -623,7 +623,7 @@ static int h245_help(struct sk_buff *skb, unsigned int protoff,
|
||||||
|
|
||||||
drop:
|
drop:
|
||||||
spin_unlock_bh(&nf_h323_lock);
|
spin_unlock_bh(&nf_h323_lock);
|
||||||
net_info_ratelimited("nf_ct_h245: packet dropped\n");
|
nf_ct_helper_log(skb, ct, "cannot process H.245 message");
|
||||||
return NF_DROP;
|
return NF_DROP;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1197,7 +1197,7 @@ static int q931_help(struct sk_buff *skb, unsigned int protoff,
|
||||||
|
|
||||||
drop:
|
drop:
|
||||||
spin_unlock_bh(&nf_h323_lock);
|
spin_unlock_bh(&nf_h323_lock);
|
||||||
net_info_ratelimited("nf_ct_q931: packet dropped\n");
|
nf_ct_helper_log(skb, ct, "cannot process Q.931 message");
|
||||||
return NF_DROP;
|
return NF_DROP;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1795,7 +1795,7 @@ static int ras_help(struct sk_buff *skb, unsigned int protoff,
|
||||||
|
|
||||||
drop:
|
drop:
|
||||||
spin_unlock_bh(&nf_h323_lock);
|
spin_unlock_bh(&nf_h323_lock);
|
||||||
net_info_ratelimited("nf_ct_ras: packet dropped\n");
|
nf_ct_helper_log(skb, ct, "cannot process RAS message");
|
||||||
return NF_DROP;
|
return NF_DROP;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -28,6 +28,7 @@
|
||||||
#include <net/netfilter/nf_conntrack_helper.h>
|
#include <net/netfilter/nf_conntrack_helper.h>
|
||||||
#include <net/netfilter/nf_conntrack_core.h>
|
#include <net/netfilter/nf_conntrack_core.h>
|
||||||
#include <net/netfilter/nf_conntrack_extend.h>
|
#include <net/netfilter/nf_conntrack_extend.h>
|
||||||
|
#include <net/netfilter/nf_log.h>
|
||||||
|
|
||||||
static DEFINE_MUTEX(nf_ct_helper_mutex);
|
static DEFINE_MUTEX(nf_ct_helper_mutex);
|
||||||
struct hlist_head *nf_ct_helper_hash __read_mostly;
|
struct hlist_head *nf_ct_helper_hash __read_mostly;
|
||||||
|
@ -334,6 +335,24 @@ nf_ct_helper_expectfn_find_by_symbol(const void *symbol)
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(nf_ct_helper_expectfn_find_by_symbol);
|
EXPORT_SYMBOL_GPL(nf_ct_helper_expectfn_find_by_symbol);
|
||||||
|
|
||||||
|
__printf(3, 4)
|
||||||
|
void nf_ct_helper_log(struct sk_buff *skb, const struct nf_conn *ct,
|
||||||
|
const char *fmt, ...)
|
||||||
|
{
|
||||||
|
const struct nf_conn_help *help;
|
||||||
|
const struct nf_conntrack_helper *helper;
|
||||||
|
|
||||||
|
/* Called from the helper function, this call never fails */
|
||||||
|
help = nfct_help(ct);
|
||||||
|
|
||||||
|
/* rcu_read_lock()ed by nf_hook_slow */
|
||||||
|
helper = rcu_dereference(help->helper);
|
||||||
|
|
||||||
|
nf_log_packet(nf_ct_l3num(ct), 0, skb, NULL, NULL, NULL,
|
||||||
|
"nf_ct_%s: dropping packet: %s ", helper->name, fmt);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(nf_ct_helper_log);
|
||||||
|
|
||||||
int nf_conntrack_helper_register(struct nf_conntrack_helper *me)
|
int nf_conntrack_helper_register(struct nf_conntrack_helper *me)
|
||||||
{
|
{
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
|
@ -194,6 +194,8 @@ static int help(struct sk_buff *skb, unsigned int protoff,
|
||||||
|
|
||||||
exp = nf_ct_expect_alloc(ct);
|
exp = nf_ct_expect_alloc(ct);
|
||||||
if (exp == NULL) {
|
if (exp == NULL) {
|
||||||
|
nf_ct_helper_log(skb, ct,
|
||||||
|
"cannot alloc expectation");
|
||||||
ret = NF_DROP;
|
ret = NF_DROP;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
@ -210,8 +212,11 @@ static int help(struct sk_buff *skb, unsigned int protoff,
|
||||||
addr_beg_p - ib_ptr,
|
addr_beg_p - ib_ptr,
|
||||||
addr_end_p - addr_beg_p,
|
addr_end_p - addr_beg_p,
|
||||||
exp);
|
exp);
|
||||||
else if (nf_ct_expect_related(exp) != 0)
|
else if (nf_ct_expect_related(exp) != 0) {
|
||||||
|
nf_ct_helper_log(skb, ct,
|
||||||
|
"cannot add expectation");
|
||||||
ret = NF_DROP;
|
ret = NF_DROP;
|
||||||
|
}
|
||||||
nf_ct_expect_put(exp);
|
nf_ct_expect_put(exp);
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1256,13 +1256,13 @@ ctnetlink_parse_nat_setup(struct nf_conn *ct,
|
||||||
if (!parse_nat_setup) {
|
if (!parse_nat_setup) {
|
||||||
#ifdef CONFIG_MODULES
|
#ifdef CONFIG_MODULES
|
||||||
rcu_read_unlock();
|
rcu_read_unlock();
|
||||||
nfnl_unlock();
|
nfnl_unlock(NFNL_SUBSYS_CTNETLINK);
|
||||||
if (request_module("nf-nat") < 0) {
|
if (request_module("nf-nat") < 0) {
|
||||||
nfnl_lock();
|
nfnl_lock(NFNL_SUBSYS_CTNETLINK);
|
||||||
rcu_read_lock();
|
rcu_read_lock();
|
||||||
return -EOPNOTSUPP;
|
return -EOPNOTSUPP;
|
||||||
}
|
}
|
||||||
nfnl_lock();
|
nfnl_lock(NFNL_SUBSYS_CTNETLINK);
|
||||||
rcu_read_lock();
|
rcu_read_lock();
|
||||||
if (nfnetlink_parse_nat_setup_hook)
|
if (nfnetlink_parse_nat_setup_hook)
|
||||||
return -EAGAIN;
|
return -EAGAIN;
|
||||||
|
@ -1274,13 +1274,13 @@ ctnetlink_parse_nat_setup(struct nf_conn *ct,
|
||||||
if (err == -EAGAIN) {
|
if (err == -EAGAIN) {
|
||||||
#ifdef CONFIG_MODULES
|
#ifdef CONFIG_MODULES
|
||||||
rcu_read_unlock();
|
rcu_read_unlock();
|
||||||
nfnl_unlock();
|
nfnl_unlock(NFNL_SUBSYS_CTNETLINK);
|
||||||
if (request_module("nf-nat-%u", nf_ct_l3num(ct)) < 0) {
|
if (request_module("nf-nat-%u", nf_ct_l3num(ct)) < 0) {
|
||||||
nfnl_lock();
|
nfnl_lock(NFNL_SUBSYS_CTNETLINK);
|
||||||
rcu_read_lock();
|
rcu_read_lock();
|
||||||
return -EOPNOTSUPP;
|
return -EOPNOTSUPP;
|
||||||
}
|
}
|
||||||
nfnl_lock();
|
nfnl_lock(NFNL_SUBSYS_CTNETLINK);
|
||||||
rcu_read_lock();
|
rcu_read_lock();
|
||||||
#else
|
#else
|
||||||
err = -EOPNOTSUPP;
|
err = -EOPNOTSUPP;
|
||||||
|
|
|
@ -14,7 +14,7 @@
|
||||||
* Limitations:
|
* Limitations:
|
||||||
* - We blindly assume that control connections are always
|
* - We blindly assume that control connections are always
|
||||||
* established in PNS->PAC direction. This is a violation
|
* established in PNS->PAC direction. This is a violation
|
||||||
* of RFFC2673
|
* of RFC 2637
|
||||||
* - We can only support one single call within each session
|
* - We can only support one single call within each session
|
||||||
* TODO:
|
* TODO:
|
||||||
* - testing of incoming PPTP calls
|
* - testing of incoming PPTP calls
|
||||||
|
|
|
@ -138,6 +138,7 @@ static int help(struct sk_buff *skb,
|
||||||
|
|
||||||
exp = nf_ct_expect_alloc(ct);
|
exp = nf_ct_expect_alloc(ct);
|
||||||
if (exp == NULL) {
|
if (exp == NULL) {
|
||||||
|
nf_ct_helper_log(skb, ct, "cannot alloc expectation");
|
||||||
ret = NF_DROP;
|
ret = NF_DROP;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
@ -151,8 +152,10 @@ static int help(struct sk_buff *skb,
|
||||||
nf_ct_dump_tuple(&exp->tuple);
|
nf_ct_dump_tuple(&exp->tuple);
|
||||||
|
|
||||||
/* Can't expect this? Best to drop packet now. */
|
/* Can't expect this? Best to drop packet now. */
|
||||||
if (nf_ct_expect_related(exp) != 0)
|
if (nf_ct_expect_related(exp) != 0) {
|
||||||
|
nf_ct_helper_log(skb, ct, "cannot add expectation");
|
||||||
ret = NF_DROP;
|
ret = NF_DROP;
|
||||||
|
}
|
||||||
|
|
||||||
nf_ct_expect_put(exp);
|
nf_ct_expect_put(exp);
|
||||||
|
|
||||||
|
|
|
@ -1095,8 +1095,10 @@ static int process_sdp(struct sk_buff *skb, unsigned int protoff,
|
||||||
port = simple_strtoul(*dptr + mediaoff, NULL, 10);
|
port = simple_strtoul(*dptr + mediaoff, NULL, 10);
|
||||||
if (port == 0)
|
if (port == 0)
|
||||||
continue;
|
continue;
|
||||||
if (port < 1024 || port > 65535)
|
if (port < 1024 || port > 65535) {
|
||||||
|
nf_ct_helper_log(skb, ct, "wrong port %u", port);
|
||||||
return NF_DROP;
|
return NF_DROP;
|
||||||
|
}
|
||||||
|
|
||||||
/* The media description overrides the session description. */
|
/* The media description overrides the session description. */
|
||||||
maddr_len = 0;
|
maddr_len = 0;
|
||||||
|
@ -1107,15 +1109,20 @@ static int process_sdp(struct sk_buff *skb, unsigned int protoff,
|
||||||
memcpy(&rtp_addr, &maddr, sizeof(rtp_addr));
|
memcpy(&rtp_addr, &maddr, sizeof(rtp_addr));
|
||||||
} else if (caddr_len)
|
} else if (caddr_len)
|
||||||
memcpy(&rtp_addr, &caddr, sizeof(rtp_addr));
|
memcpy(&rtp_addr, &caddr, sizeof(rtp_addr));
|
||||||
else
|
else {
|
||||||
|
nf_ct_helper_log(skb, ct, "cannot parse SDP message");
|
||||||
return NF_DROP;
|
return NF_DROP;
|
||||||
|
}
|
||||||
|
|
||||||
ret = set_expected_rtp_rtcp(skb, protoff, dataoff,
|
ret = set_expected_rtp_rtcp(skb, protoff, dataoff,
|
||||||
dptr, datalen,
|
dptr, datalen,
|
||||||
&rtp_addr, htons(port), t->class,
|
&rtp_addr, htons(port), t->class,
|
||||||
mediaoff, medialen);
|
mediaoff, medialen);
|
||||||
if (ret != NF_ACCEPT)
|
if (ret != NF_ACCEPT) {
|
||||||
|
nf_ct_helper_log(skb, ct,
|
||||||
|
"cannot add expectation for voice");
|
||||||
return ret;
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
/* Update media connection address if present */
|
/* Update media connection address if present */
|
||||||
if (maddr_len && nf_nat_sdp_addr && ct->status & IPS_NAT_MASK) {
|
if (maddr_len && nf_nat_sdp_addr && ct->status & IPS_NAT_MASK) {
|
||||||
|
@ -1123,8 +1130,10 @@ static int process_sdp(struct sk_buff *skb, unsigned int protoff,
|
||||||
dptr, datalen, mediaoff,
|
dptr, datalen, mediaoff,
|
||||||
SDP_HDR_CONNECTION, SDP_HDR_MEDIA,
|
SDP_HDR_CONNECTION, SDP_HDR_MEDIA,
|
||||||
&rtp_addr);
|
&rtp_addr);
|
||||||
if (ret != NF_ACCEPT)
|
if (ret != NF_ACCEPT) {
|
||||||
|
nf_ct_helper_log(skb, ct, "cannot mangle SDP");
|
||||||
return ret;
|
return ret;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
|
@ -1258,9 +1267,10 @@ static int process_register_request(struct sk_buff *skb, unsigned int protoff,
|
||||||
ret = ct_sip_parse_header_uri(ct, *dptr, NULL, *datalen,
|
ret = ct_sip_parse_header_uri(ct, *dptr, NULL, *datalen,
|
||||||
SIP_HDR_CONTACT, NULL,
|
SIP_HDR_CONTACT, NULL,
|
||||||
&matchoff, &matchlen, &daddr, &port);
|
&matchoff, &matchlen, &daddr, &port);
|
||||||
if (ret < 0)
|
if (ret < 0) {
|
||||||
|
nf_ct_helper_log(skb, ct, "cannot parse contact");
|
||||||
return NF_DROP;
|
return NF_DROP;
|
||||||
else if (ret == 0)
|
} else if (ret == 0)
|
||||||
return NF_ACCEPT;
|
return NF_ACCEPT;
|
||||||
|
|
||||||
/* We don't support third-party registrations */
|
/* We don't support third-party registrations */
|
||||||
|
@ -1273,8 +1283,10 @@ static int process_register_request(struct sk_buff *skb, unsigned int protoff,
|
||||||
|
|
||||||
if (ct_sip_parse_numerical_param(ct, *dptr,
|
if (ct_sip_parse_numerical_param(ct, *dptr,
|
||||||
matchoff + matchlen, *datalen,
|
matchoff + matchlen, *datalen,
|
||||||
"expires=", NULL, NULL, &expires) < 0)
|
"expires=", NULL, NULL, &expires) < 0) {
|
||||||
|
nf_ct_helper_log(skb, ct, "cannot parse expires");
|
||||||
return NF_DROP;
|
return NF_DROP;
|
||||||
|
}
|
||||||
|
|
||||||
if (expires == 0) {
|
if (expires == 0) {
|
||||||
ret = NF_ACCEPT;
|
ret = NF_ACCEPT;
|
||||||
|
@ -1282,8 +1294,10 @@ static int process_register_request(struct sk_buff *skb, unsigned int protoff,
|
||||||
}
|
}
|
||||||
|
|
||||||
exp = nf_ct_expect_alloc(ct);
|
exp = nf_ct_expect_alloc(ct);
|
||||||
if (!exp)
|
if (!exp) {
|
||||||
|
nf_ct_helper_log(skb, ct, "cannot alloc expectation");
|
||||||
return NF_DROP;
|
return NF_DROP;
|
||||||
|
}
|
||||||
|
|
||||||
saddr = NULL;
|
saddr = NULL;
|
||||||
if (sip_direct_signalling)
|
if (sip_direct_signalling)
|
||||||
|
@ -1300,9 +1314,10 @@ static int process_register_request(struct sk_buff *skb, unsigned int protoff,
|
||||||
ret = nf_nat_sip_expect(skb, protoff, dataoff, dptr, datalen,
|
ret = nf_nat_sip_expect(skb, protoff, dataoff, dptr, datalen,
|
||||||
exp, matchoff, matchlen);
|
exp, matchoff, matchlen);
|
||||||
else {
|
else {
|
||||||
if (nf_ct_expect_related(exp) != 0)
|
if (nf_ct_expect_related(exp) != 0) {
|
||||||
|
nf_ct_helper_log(skb, ct, "cannot add expectation");
|
||||||
ret = NF_DROP;
|
ret = NF_DROP;
|
||||||
else
|
} else
|
||||||
ret = NF_ACCEPT;
|
ret = NF_ACCEPT;
|
||||||
}
|
}
|
||||||
nf_ct_expect_put(exp);
|
nf_ct_expect_put(exp);
|
||||||
|
@ -1356,9 +1371,10 @@ static int process_register_response(struct sk_buff *skb, unsigned int protoff,
|
||||||
SIP_HDR_CONTACT, &in_contact,
|
SIP_HDR_CONTACT, &in_contact,
|
||||||
&matchoff, &matchlen,
|
&matchoff, &matchlen,
|
||||||
&addr, &port);
|
&addr, &port);
|
||||||
if (ret < 0)
|
if (ret < 0) {
|
||||||
|
nf_ct_helper_log(skb, ct, "cannot parse contact");
|
||||||
return NF_DROP;
|
return NF_DROP;
|
||||||
else if (ret == 0)
|
} else if (ret == 0)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/* We don't support third-party registrations */
|
/* We don't support third-party registrations */
|
||||||
|
@ -1373,8 +1389,10 @@ static int process_register_response(struct sk_buff *skb, unsigned int protoff,
|
||||||
matchoff + matchlen,
|
matchoff + matchlen,
|
||||||
*datalen, "expires=",
|
*datalen, "expires=",
|
||||||
NULL, NULL, &c_expires);
|
NULL, NULL, &c_expires);
|
||||||
if (ret < 0)
|
if (ret < 0) {
|
||||||
|
nf_ct_helper_log(skb, ct, "cannot parse expires");
|
||||||
return NF_DROP;
|
return NF_DROP;
|
||||||
|
}
|
||||||
if (c_expires == 0)
|
if (c_expires == 0)
|
||||||
break;
|
break;
|
||||||
if (refresh_signalling_expectation(ct, &addr, proto, port,
|
if (refresh_signalling_expectation(ct, &addr, proto, port,
|
||||||
|
@ -1408,15 +1426,21 @@ static int process_sip_response(struct sk_buff *skb, unsigned int protoff,
|
||||||
if (*datalen < strlen("SIP/2.0 200"))
|
if (*datalen < strlen("SIP/2.0 200"))
|
||||||
return NF_ACCEPT;
|
return NF_ACCEPT;
|
||||||
code = simple_strtoul(*dptr + strlen("SIP/2.0 "), NULL, 10);
|
code = simple_strtoul(*dptr + strlen("SIP/2.0 "), NULL, 10);
|
||||||
if (!code)
|
if (!code) {
|
||||||
|
nf_ct_helper_log(skb, ct, "cannot get code");
|
||||||
return NF_DROP;
|
return NF_DROP;
|
||||||
|
}
|
||||||
|
|
||||||
if (ct_sip_get_header(ct, *dptr, 0, *datalen, SIP_HDR_CSEQ,
|
if (ct_sip_get_header(ct, *dptr, 0, *datalen, SIP_HDR_CSEQ,
|
||||||
&matchoff, &matchlen) <= 0)
|
&matchoff, &matchlen) <= 0) {
|
||||||
|
nf_ct_helper_log(skb, ct, "cannot parse cseq");
|
||||||
return NF_DROP;
|
return NF_DROP;
|
||||||
|
}
|
||||||
cseq = simple_strtoul(*dptr + matchoff, NULL, 10);
|
cseq = simple_strtoul(*dptr + matchoff, NULL, 10);
|
||||||
if (!cseq)
|
if (!cseq) {
|
||||||
|
nf_ct_helper_log(skb, ct, "cannot get cseq");
|
||||||
return NF_DROP;
|
return NF_DROP;
|
||||||
|
}
|
||||||
matchend = matchoff + matchlen + 1;
|
matchend = matchoff + matchlen + 1;
|
||||||
|
|
||||||
for (i = 0; i < ARRAY_SIZE(sip_handlers); i++) {
|
for (i = 0; i < ARRAY_SIZE(sip_handlers); i++) {
|
||||||
|
@ -1471,11 +1495,15 @@ static int process_sip_request(struct sk_buff *skb, unsigned int protoff,
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (ct_sip_get_header(ct, *dptr, 0, *datalen, SIP_HDR_CSEQ,
|
if (ct_sip_get_header(ct, *dptr, 0, *datalen, SIP_HDR_CSEQ,
|
||||||
&matchoff, &matchlen) <= 0)
|
&matchoff, &matchlen) <= 0) {
|
||||||
|
nf_ct_helper_log(skb, ct, "cannot parse cseq");
|
||||||
return NF_DROP;
|
return NF_DROP;
|
||||||
|
}
|
||||||
cseq = simple_strtoul(*dptr + matchoff, NULL, 10);
|
cseq = simple_strtoul(*dptr + matchoff, NULL, 10);
|
||||||
if (!cseq)
|
if (!cseq) {
|
||||||
|
nf_ct_helper_log(skb, ct, "cannot get cseq");
|
||||||
return NF_DROP;
|
return NF_DROP;
|
||||||
|
}
|
||||||
|
|
||||||
return handler->request(skb, protoff, dataoff, dptr, datalen,
|
return handler->request(skb, protoff, dataoff, dptr, datalen,
|
||||||
cseq);
|
cseq);
|
||||||
|
@ -1498,8 +1526,10 @@ static int process_sip_msg(struct sk_buff *skb, struct nf_conn *ct,
|
||||||
if (ret == NF_ACCEPT && ct->status & IPS_NAT_MASK) {
|
if (ret == NF_ACCEPT && ct->status & IPS_NAT_MASK) {
|
||||||
nf_nat_sip = rcu_dereference(nf_nat_sip_hook);
|
nf_nat_sip = rcu_dereference(nf_nat_sip_hook);
|
||||||
if (nf_nat_sip && !nf_nat_sip(skb, protoff, dataoff,
|
if (nf_nat_sip && !nf_nat_sip(skb, protoff, dataoff,
|
||||||
dptr, datalen))
|
dptr, datalen)) {
|
||||||
|
nf_ct_helper_log(skb, ct, "cannot NAT SIP message");
|
||||||
ret = NF_DROP;
|
ret = NF_DROP;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -1563,11 +1593,14 @@ static int sip_help_tcp(struct sk_buff *skb, unsigned int protoff,
|
||||||
end += strlen("\r\n\r\n") + clen;
|
end += strlen("\r\n\r\n") + clen;
|
||||||
|
|
||||||
msglen = origlen = end - dptr;
|
msglen = origlen = end - dptr;
|
||||||
if (msglen > datalen)
|
if (msglen > datalen) {
|
||||||
|
nf_ct_helper_log(skb, ct, "incomplete/bad SIP message");
|
||||||
return NF_DROP;
|
return NF_DROP;
|
||||||
|
}
|
||||||
|
|
||||||
ret = process_sip_msg(skb, ct, protoff, dataoff,
|
ret = process_sip_msg(skb, ct, protoff, dataoff,
|
||||||
&dptr, &msglen);
|
&dptr, &msglen);
|
||||||
|
/* process_sip_* functions report why this packet is dropped */
|
||||||
if (ret != NF_ACCEPT)
|
if (ret != NF_ACCEPT)
|
||||||
break;
|
break;
|
||||||
diff = msglen - origlen;
|
diff = msglen - origlen;
|
||||||
|
|
|
@ -60,8 +60,10 @@ static int tftp_help(struct sk_buff *skb,
|
||||||
nf_ct_dump_tuple(&ct->tuplehash[IP_CT_DIR_REPLY].tuple);
|
nf_ct_dump_tuple(&ct->tuplehash[IP_CT_DIR_REPLY].tuple);
|
||||||
|
|
||||||
exp = nf_ct_expect_alloc(ct);
|
exp = nf_ct_expect_alloc(ct);
|
||||||
if (exp == NULL)
|
if (exp == NULL) {
|
||||||
|
nf_ct_helper_log(skb, ct, "cannot alloc expectation");
|
||||||
return NF_DROP;
|
return NF_DROP;
|
||||||
|
}
|
||||||
tuple = &ct->tuplehash[IP_CT_DIR_REPLY].tuple;
|
tuple = &ct->tuplehash[IP_CT_DIR_REPLY].tuple;
|
||||||
nf_ct_expect_init(exp, NF_CT_EXPECT_CLASS_DEFAULT,
|
nf_ct_expect_init(exp, NF_CT_EXPECT_CLASS_DEFAULT,
|
||||||
nf_ct_l3num(ct),
|
nf_ct_l3num(ct),
|
||||||
|
@ -74,8 +76,10 @@ static int tftp_help(struct sk_buff *skb,
|
||||||
nf_nat_tftp = rcu_dereference(nf_nat_tftp_hook);
|
nf_nat_tftp = rcu_dereference(nf_nat_tftp_hook);
|
||||||
if (nf_nat_tftp && ct->status & IPS_NAT_MASK)
|
if (nf_nat_tftp && ct->status & IPS_NAT_MASK)
|
||||||
ret = nf_nat_tftp(skb, ctinfo, exp);
|
ret = nf_nat_tftp(skb, ctinfo, exp);
|
||||||
else if (nf_ct_expect_related(exp) != 0)
|
else if (nf_ct_expect_related(exp) != 0) {
|
||||||
|
nf_ct_helper_log(skb, ct, "cannot add expectation");
|
||||||
ret = NF_DROP;
|
ret = NF_DROP;
|
||||||
|
}
|
||||||
nf_ct_expect_put(exp);
|
nf_ct_expect_put(exp);
|
||||||
break;
|
break;
|
||||||
case TFTP_OPCODE_DATA:
|
case TFTP_OPCODE_DATA:
|
||||||
|
|
|
@ -56,15 +56,19 @@ static unsigned int help(struct sk_buff *skb,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (port == 0)
|
if (port == 0) {
|
||||||
|
nf_ct_helper_log(skb, exp->master, "all ports in use");
|
||||||
return NF_DROP;
|
return NF_DROP;
|
||||||
|
}
|
||||||
|
|
||||||
sprintf(buffer, "%u", port);
|
sprintf(buffer, "%u", port);
|
||||||
ret = nf_nat_mangle_udp_packet(skb, exp->master, ctinfo,
|
ret = nf_nat_mangle_udp_packet(skb, exp->master, ctinfo,
|
||||||
protoff, matchoff, matchlen,
|
protoff, matchoff, matchlen,
|
||||||
buffer, strlen(buffer));
|
buffer, strlen(buffer));
|
||||||
if (ret != NF_ACCEPT)
|
if (ret != NF_ACCEPT) {
|
||||||
|
nf_ct_helper_log(skb, exp->master, "cannot mangle packet");
|
||||||
nf_ct_unexpect_related(exp);
|
nf_ct_unexpect_related(exp);
|
||||||
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -96,8 +96,10 @@ static unsigned int nf_nat_ftp(struct sk_buff *skb,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (port == 0)
|
if (port == 0) {
|
||||||
|
nf_ct_helper_log(skb, ct, "all ports in use");
|
||||||
return NF_DROP;
|
return NF_DROP;
|
||||||
|
}
|
||||||
|
|
||||||
buflen = nf_nat_ftp_fmt_cmd(ct, type, buffer, sizeof(buffer),
|
buflen = nf_nat_ftp_fmt_cmd(ct, type, buffer, sizeof(buffer),
|
||||||
&newaddr, port);
|
&newaddr, port);
|
||||||
|
@ -113,6 +115,7 @@ static unsigned int nf_nat_ftp(struct sk_buff *skb,
|
||||||
return NF_ACCEPT;
|
return NF_ACCEPT;
|
||||||
|
|
||||||
out:
|
out:
|
||||||
|
nf_ct_helper_log(skb, ct, "cannot mangle packet");
|
||||||
nf_ct_unexpect_related(exp);
|
nf_ct_unexpect_related(exp);
|
||||||
return NF_DROP;
|
return NF_DROP;
|
||||||
}
|
}
|
||||||
|
|
|
@ -56,14 +56,18 @@ static unsigned int help(struct sk_buff *skb,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (port == 0)
|
if (port == 0) {
|
||||||
|
nf_ct_helper_log(skb, exp->master, "all ports in use");
|
||||||
return NF_DROP;
|
return NF_DROP;
|
||||||
|
}
|
||||||
|
|
||||||
ret = nf_nat_mangle_tcp_packet(skb, exp->master, ctinfo,
|
ret = nf_nat_mangle_tcp_packet(skb, exp->master, ctinfo,
|
||||||
protoff, matchoff, matchlen, buffer,
|
protoff, matchoff, matchlen, buffer,
|
||||||
strlen(buffer));
|
strlen(buffer));
|
||||||
if (ret != NF_ACCEPT)
|
if (ret != NF_ACCEPT) {
|
||||||
|
nf_ct_helper_log(skb, exp->master, "cannot mangle packet");
|
||||||
nf_ct_unexpect_related(exp);
|
nf_ct_unexpect_related(exp);
|
||||||
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -159,8 +159,10 @@ static unsigned int nf_nat_sip(struct sk_buff *skb, unsigned int protoff,
|
||||||
&matchoff, &matchlen,
|
&matchoff, &matchlen,
|
||||||
&addr, &port) > 0 &&
|
&addr, &port) > 0 &&
|
||||||
!map_addr(skb, protoff, dataoff, dptr, datalen,
|
!map_addr(skb, protoff, dataoff, dptr, datalen,
|
||||||
matchoff, matchlen, &addr, port))
|
matchoff, matchlen, &addr, port)) {
|
||||||
|
nf_ct_helper_log(skb, ct, "cannot mangle SIP message");
|
||||||
return NF_DROP;
|
return NF_DROP;
|
||||||
|
}
|
||||||
request = 1;
|
request = 1;
|
||||||
} else
|
} else
|
||||||
request = 0;
|
request = 0;
|
||||||
|
@ -193,8 +195,10 @@ static unsigned int nf_nat_sip(struct sk_buff *skb, unsigned int protoff,
|
||||||
|
|
||||||
olen = *datalen;
|
olen = *datalen;
|
||||||
if (!map_addr(skb, protoff, dataoff, dptr, datalen,
|
if (!map_addr(skb, protoff, dataoff, dptr, datalen,
|
||||||
matchoff, matchlen, &addr, port))
|
matchoff, matchlen, &addr, port)) {
|
||||||
|
nf_ct_helper_log(skb, ct, "cannot mangle Via header");
|
||||||
return NF_DROP;
|
return NF_DROP;
|
||||||
|
}
|
||||||
|
|
||||||
matchend = matchoff + matchlen + *datalen - olen;
|
matchend = matchoff + matchlen + *datalen - olen;
|
||||||
|
|
||||||
|
@ -209,8 +213,10 @@ static unsigned int nf_nat_sip(struct sk_buff *skb, unsigned int protoff,
|
||||||
&ct->tuplehash[!dir].tuple.dst.u3,
|
&ct->tuplehash[!dir].tuple.dst.u3,
|
||||||
true);
|
true);
|
||||||
if (!mangle_packet(skb, protoff, dataoff, dptr, datalen,
|
if (!mangle_packet(skb, protoff, dataoff, dptr, datalen,
|
||||||
poff, plen, buffer, buflen))
|
poff, plen, buffer, buflen)) {
|
||||||
|
nf_ct_helper_log(skb, ct, "cannot mangle maddr");
|
||||||
return NF_DROP;
|
return NF_DROP;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* The received= parameter (RFC 2361) contains the address
|
/* The received= parameter (RFC 2361) contains the address
|
||||||
|
@ -225,6 +231,7 @@ static unsigned int nf_nat_sip(struct sk_buff *skb, unsigned int protoff,
|
||||||
false);
|
false);
|
||||||
if (!mangle_packet(skb, protoff, dataoff, dptr, datalen,
|
if (!mangle_packet(skb, protoff, dataoff, dptr, datalen,
|
||||||
poff, plen, buffer, buflen))
|
poff, plen, buffer, buflen))
|
||||||
|
nf_ct_helper_log(skb, ct, "cannot mangle received");
|
||||||
return NF_DROP;
|
return NF_DROP;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -238,8 +245,10 @@ static unsigned int nf_nat_sip(struct sk_buff *skb, unsigned int protoff,
|
||||||
__be16 p = ct->tuplehash[!dir].tuple.src.u.udp.port;
|
__be16 p = ct->tuplehash[!dir].tuple.src.u.udp.port;
|
||||||
buflen = sprintf(buffer, "%u", ntohs(p));
|
buflen = sprintf(buffer, "%u", ntohs(p));
|
||||||
if (!mangle_packet(skb, protoff, dataoff, dptr, datalen,
|
if (!mangle_packet(skb, protoff, dataoff, dptr, datalen,
|
||||||
poff, plen, buffer, buflen))
|
poff, plen, buffer, buflen)) {
|
||||||
|
nf_ct_helper_log(skb, ct, "cannot mangle rport");
|
||||||
return NF_DROP;
|
return NF_DROP;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -253,27 +262,35 @@ next:
|
||||||
&addr, &port) > 0) {
|
&addr, &port) > 0) {
|
||||||
if (!map_addr(skb, protoff, dataoff, dptr, datalen,
|
if (!map_addr(skb, protoff, dataoff, dptr, datalen,
|
||||||
matchoff, matchlen,
|
matchoff, matchlen,
|
||||||
&addr, port))
|
&addr, port)) {
|
||||||
|
nf_ct_helper_log(skb, ct, "cannot mangle contact");
|
||||||
return NF_DROP;
|
return NF_DROP;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!map_sip_addr(skb, protoff, dataoff, dptr, datalen, SIP_HDR_FROM) ||
|
if (!map_sip_addr(skb, protoff, dataoff, dptr, datalen, SIP_HDR_FROM) ||
|
||||||
!map_sip_addr(skb, protoff, dataoff, dptr, datalen, SIP_HDR_TO))
|
!map_sip_addr(skb, protoff, dataoff, dptr, datalen, SIP_HDR_TO)) {
|
||||||
|
nf_ct_helper_log(skb, ct, "cannot mangle SIP from/to");
|
||||||
return NF_DROP;
|
return NF_DROP;
|
||||||
|
}
|
||||||
|
|
||||||
/* Mangle destination port for Cisco phones, then fix up checksums */
|
/* Mangle destination port for Cisco phones, then fix up checksums */
|
||||||
if (dir == IP_CT_DIR_REPLY && ct_sip_info->forced_dport) {
|
if (dir == IP_CT_DIR_REPLY && ct_sip_info->forced_dport) {
|
||||||
struct udphdr *uh;
|
struct udphdr *uh;
|
||||||
|
|
||||||
if (!skb_make_writable(skb, skb->len))
|
if (!skb_make_writable(skb, skb->len)) {
|
||||||
|
nf_ct_helper_log(skb, ct, "cannot mangle packet");
|
||||||
return NF_DROP;
|
return NF_DROP;
|
||||||
|
}
|
||||||
|
|
||||||
uh = (void *)skb->data + protoff;
|
uh = (void *)skb->data + protoff;
|
||||||
uh->dest = ct_sip_info->forced_dport;
|
uh->dest = ct_sip_info->forced_dport;
|
||||||
|
|
||||||
if (!nf_nat_mangle_udp_packet(skb, ct, ctinfo, protoff,
|
if (!nf_nat_mangle_udp_packet(skb, ct, ctinfo, protoff,
|
||||||
0, 0, NULL, 0))
|
0, 0, NULL, 0)) {
|
||||||
|
nf_ct_helper_log(skb, ct, "cannot mangle packet");
|
||||||
return NF_DROP;
|
return NF_DROP;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return NF_ACCEPT;
|
return NF_ACCEPT;
|
||||||
|
@ -372,15 +389,19 @@ static unsigned int nf_nat_sip_expect(struct sk_buff *skb, unsigned int protoff,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (port == 0)
|
if (port == 0) {
|
||||||
|
nf_ct_helper_log(skb, ct, "all ports in use for SIP");
|
||||||
return NF_DROP;
|
return NF_DROP;
|
||||||
|
}
|
||||||
|
|
||||||
if (!nf_inet_addr_cmp(&exp->tuple.dst.u3, &exp->saved_addr) ||
|
if (!nf_inet_addr_cmp(&exp->tuple.dst.u3, &exp->saved_addr) ||
|
||||||
exp->tuple.dst.u.udp.port != exp->saved_proto.udp.port) {
|
exp->tuple.dst.u.udp.port != exp->saved_proto.udp.port) {
|
||||||
buflen = sip_sprintf_addr_port(ct, buffer, &newaddr, port);
|
buflen = sip_sprintf_addr_port(ct, buffer, &newaddr, port);
|
||||||
if (!mangle_packet(skb, protoff, dataoff, dptr, datalen,
|
if (!mangle_packet(skb, protoff, dataoff, dptr, datalen,
|
||||||
matchoff, matchlen, buffer, buflen))
|
matchoff, matchlen, buffer, buflen)) {
|
||||||
|
nf_ct_helper_log(skb, ct, "cannot mangle packet");
|
||||||
goto err;
|
goto err;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return NF_ACCEPT;
|
return NF_ACCEPT;
|
||||||
|
|
||||||
|
@ -573,14 +594,18 @@ static unsigned int nf_nat_sdp_media(struct sk_buff *skb, unsigned int protoff,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (port == 0)
|
if (port == 0) {
|
||||||
|
nf_ct_helper_log(skb, ct, "all ports in use for SDP media");
|
||||||
goto err1;
|
goto err1;
|
||||||
|
}
|
||||||
|
|
||||||
/* Update media port. */
|
/* Update media port. */
|
||||||
if (rtp_exp->tuple.dst.u.udp.port != rtp_exp->saved_proto.udp.port &&
|
if (rtp_exp->tuple.dst.u.udp.port != rtp_exp->saved_proto.udp.port &&
|
||||||
!nf_nat_sdp_port(skb, protoff, dataoff, dptr, datalen,
|
!nf_nat_sdp_port(skb, protoff, dataoff, dptr, datalen,
|
||||||
mediaoff, medialen, port))
|
mediaoff, medialen, port)) {
|
||||||
|
nf_ct_helper_log(skb, ct, "cannot mangle SDP message");
|
||||||
goto err2;
|
goto err2;
|
||||||
|
}
|
||||||
|
|
||||||
return NF_ACCEPT;
|
return NF_ACCEPT;
|
||||||
|
|
||||||
|
|
|
@ -28,8 +28,10 @@ static unsigned int help(struct sk_buff *skb,
|
||||||
= ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u.udp.port;
|
= ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u.udp.port;
|
||||||
exp->dir = IP_CT_DIR_REPLY;
|
exp->dir = IP_CT_DIR_REPLY;
|
||||||
exp->expectfn = nf_nat_follow_master;
|
exp->expectfn = nf_nat_follow_master;
|
||||||
if (nf_ct_expect_related(exp) != 0)
|
if (nf_ct_expect_related(exp) != 0) {
|
||||||
|
nf_ct_helper_log(skb, exp->master, "cannot add expectation");
|
||||||
return NF_DROP;
|
return NF_DROP;
|
||||||
|
}
|
||||||
return NF_ACCEPT;
|
return NF_ACCEPT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -36,8 +36,10 @@ MODULE_ALIAS_NET_PF_PROTO(PF_NETLINK, NETLINK_NETFILTER);
|
||||||
|
|
||||||
static char __initdata nfversion[] = "0.30";
|
static char __initdata nfversion[] = "0.30";
|
||||||
|
|
||||||
static const struct nfnetlink_subsystem __rcu *subsys_table[NFNL_SUBSYS_COUNT];
|
static struct {
|
||||||
static DEFINE_MUTEX(nfnl_mutex);
|
struct mutex mutex;
|
||||||
|
const struct nfnetlink_subsystem __rcu *subsys;
|
||||||
|
} table[NFNL_SUBSYS_COUNT];
|
||||||
|
|
||||||
static const int nfnl_group2type[NFNLGRP_MAX+1] = {
|
static const int nfnl_group2type[NFNLGRP_MAX+1] = {
|
||||||
[NFNLGRP_CONNTRACK_NEW] = NFNL_SUBSYS_CTNETLINK,
|
[NFNLGRP_CONNTRACK_NEW] = NFNL_SUBSYS_CTNETLINK,
|
||||||
|
@ -48,27 +50,32 @@ static const int nfnl_group2type[NFNLGRP_MAX+1] = {
|
||||||
[NFNLGRP_CONNTRACK_EXP_DESTROY] = NFNL_SUBSYS_CTNETLINK_EXP,
|
[NFNLGRP_CONNTRACK_EXP_DESTROY] = NFNL_SUBSYS_CTNETLINK_EXP,
|
||||||
};
|
};
|
||||||
|
|
||||||
void nfnl_lock(void)
|
void nfnl_lock(__u8 subsys_id)
|
||||||
{
|
{
|
||||||
mutex_lock(&nfnl_mutex);
|
mutex_lock(&table[subsys_id].mutex);
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(nfnl_lock);
|
EXPORT_SYMBOL_GPL(nfnl_lock);
|
||||||
|
|
||||||
void nfnl_unlock(void)
|
void nfnl_unlock(__u8 subsys_id)
|
||||||
{
|
{
|
||||||
mutex_unlock(&nfnl_mutex);
|
mutex_unlock(&table[subsys_id].mutex);
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(nfnl_unlock);
|
EXPORT_SYMBOL_GPL(nfnl_unlock);
|
||||||
|
|
||||||
|
static struct mutex *nfnl_get_lock(__u8 subsys_id)
|
||||||
|
{
|
||||||
|
return &table[subsys_id].mutex;
|
||||||
|
}
|
||||||
|
|
||||||
int nfnetlink_subsys_register(const struct nfnetlink_subsystem *n)
|
int nfnetlink_subsys_register(const struct nfnetlink_subsystem *n)
|
||||||
{
|
{
|
||||||
nfnl_lock();
|
nfnl_lock(n->subsys_id);
|
||||||
if (subsys_table[n->subsys_id]) {
|
if (table[n->subsys_id].subsys) {
|
||||||
nfnl_unlock();
|
nfnl_unlock(n->subsys_id);
|
||||||
return -EBUSY;
|
return -EBUSY;
|
||||||
}
|
}
|
||||||
rcu_assign_pointer(subsys_table[n->subsys_id], n);
|
rcu_assign_pointer(table[n->subsys_id].subsys, n);
|
||||||
nfnl_unlock();
|
nfnl_unlock(n->subsys_id);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -76,9 +83,9 @@ EXPORT_SYMBOL_GPL(nfnetlink_subsys_register);
|
||||||
|
|
||||||
int nfnetlink_subsys_unregister(const struct nfnetlink_subsystem *n)
|
int nfnetlink_subsys_unregister(const struct nfnetlink_subsystem *n)
|
||||||
{
|
{
|
||||||
nfnl_lock();
|
nfnl_lock(n->subsys_id);
|
||||||
subsys_table[n->subsys_id] = NULL;
|
table[n->subsys_id].subsys = NULL;
|
||||||
nfnl_unlock();
|
nfnl_unlock(n->subsys_id);
|
||||||
synchronize_rcu();
|
synchronize_rcu();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -91,7 +98,7 @@ static inline const struct nfnetlink_subsystem *nfnetlink_get_subsys(u_int16_t t
|
||||||
if (subsys_id >= NFNL_SUBSYS_COUNT)
|
if (subsys_id >= NFNL_SUBSYS_COUNT)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
return rcu_dereference(subsys_table[subsys_id]);
|
return rcu_dereference(table[subsys_id].subsys);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline const struct nfnl_callback *
|
static inline const struct nfnl_callback *
|
||||||
|
@ -175,6 +182,7 @@ replay:
|
||||||
struct nlattr *cda[ss->cb[cb_id].attr_count + 1];
|
struct nlattr *cda[ss->cb[cb_id].attr_count + 1];
|
||||||
struct nlattr *attr = (void *)nlh + min_len;
|
struct nlattr *attr = (void *)nlh + min_len;
|
||||||
int attrlen = nlh->nlmsg_len - min_len;
|
int attrlen = nlh->nlmsg_len - min_len;
|
||||||
|
__u8 subsys_id = NFNL_SUBSYS_ID(type);
|
||||||
|
|
||||||
err = nla_parse(cda, ss->cb[cb_id].attr_count,
|
err = nla_parse(cda, ss->cb[cb_id].attr_count,
|
||||||
attr, attrlen, ss->cb[cb_id].policy);
|
attr, attrlen, ss->cb[cb_id].policy);
|
||||||
|
@ -189,10 +197,9 @@ replay:
|
||||||
rcu_read_unlock();
|
rcu_read_unlock();
|
||||||
} else {
|
} else {
|
||||||
rcu_read_unlock();
|
rcu_read_unlock();
|
||||||
nfnl_lock();
|
nfnl_lock(subsys_id);
|
||||||
if (rcu_dereference_protected(
|
if (rcu_dereference_protected(table[subsys_id].subsys,
|
||||||
subsys_table[NFNL_SUBSYS_ID(type)],
|
lockdep_is_held(nfnl_get_lock(subsys_id))) != ss ||
|
||||||
lockdep_is_held(&nfnl_mutex)) != ss ||
|
|
||||||
nfnetlink_find_client(type, ss) != nc)
|
nfnetlink_find_client(type, ss) != nc)
|
||||||
err = -EAGAIN;
|
err = -EAGAIN;
|
||||||
else if (nc->call)
|
else if (nc->call)
|
||||||
|
@ -200,7 +207,7 @@ replay:
|
||||||
(const struct nlattr **)cda);
|
(const struct nlattr **)cda);
|
||||||
else
|
else
|
||||||
err = -EINVAL;
|
err = -EINVAL;
|
||||||
nfnl_unlock();
|
nfnl_unlock(subsys_id);
|
||||||
}
|
}
|
||||||
if (err == -EAGAIN)
|
if (err == -EAGAIN)
|
||||||
goto replay;
|
goto replay;
|
||||||
|
@ -267,6 +274,11 @@ static struct pernet_operations nfnetlink_net_ops = {
|
||||||
|
|
||||||
static int __init nfnetlink_init(void)
|
static int __init nfnetlink_init(void)
|
||||||
{
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i=0; i<NFNL_SUBSYS_COUNT; i++)
|
||||||
|
mutex_init(&table[i].mutex);
|
||||||
|
|
||||||
pr_info("Netfilter messages via NETLINK v%s.\n", nfversion);
|
pr_info("Netfilter messages via NETLINK v%s.\n", nfversion);
|
||||||
return register_pernet_subsys(&nfnetlink_net_ops);
|
return register_pernet_subsys(&nfnetlink_net_ops);
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,12 +20,8 @@
|
||||||
#include <net/netfilter/nf_conntrack_timeout.h>
|
#include <net/netfilter/nf_conntrack_timeout.h>
|
||||||
#include <net/netfilter/nf_conntrack_zones.h>
|
#include <net/netfilter/nf_conntrack_zones.h>
|
||||||
|
|
||||||
static unsigned int xt_ct_target_v0(struct sk_buff *skb,
|
static inline int xt_ct_target(struct sk_buff *skb, struct nf_conn *ct)
|
||||||
const struct xt_action_param *par)
|
|
||||||
{
|
{
|
||||||
const struct xt_ct_target_info *info = par->targinfo;
|
|
||||||
struct nf_conn *ct = info->ct;
|
|
||||||
|
|
||||||
/* Previously seen (loopback)? Ignore. */
|
/* Previously seen (loopback)? Ignore. */
|
||||||
if (skb->nfct != NULL)
|
if (skb->nfct != NULL)
|
||||||
return XT_CONTINUE;
|
return XT_CONTINUE;
|
||||||
|
@ -37,21 +33,22 @@ static unsigned int xt_ct_target_v0(struct sk_buff *skb,
|
||||||
return XT_CONTINUE;
|
return XT_CONTINUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static unsigned int xt_ct_target_v0(struct sk_buff *skb,
|
||||||
|
const struct xt_action_param *par)
|
||||||
|
{
|
||||||
|
const struct xt_ct_target_info *info = par->targinfo;
|
||||||
|
struct nf_conn *ct = info->ct;
|
||||||
|
|
||||||
|
return xt_ct_target(skb, ct);
|
||||||
|
}
|
||||||
|
|
||||||
static unsigned int xt_ct_target_v1(struct sk_buff *skb,
|
static unsigned int xt_ct_target_v1(struct sk_buff *skb,
|
||||||
const struct xt_action_param *par)
|
const struct xt_action_param *par)
|
||||||
{
|
{
|
||||||
const struct xt_ct_target_info_v1 *info = par->targinfo;
|
const struct xt_ct_target_info_v1 *info = par->targinfo;
|
||||||
struct nf_conn *ct = info->ct;
|
struct nf_conn *ct = info->ct;
|
||||||
|
|
||||||
/* Previously seen (loopback)? Ignore. */
|
return xt_ct_target(skb, ct);
|
||||||
if (skb->nfct != NULL)
|
|
||||||
return XT_CONTINUE;
|
|
||||||
|
|
||||||
atomic_inc(&ct->ct_general.use);
|
|
||||||
skb->nfct = &ct->ct_general;
|
|
||||||
skb->nfctinfo = IP_CT_NEW;
|
|
||||||
|
|
||||||
return XT_CONTINUE;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static u8 xt_ct_find_proto(const struct xt_tgchk_param *par)
|
static u8 xt_ct_find_proto(const struct xt_tgchk_param *par)
|
||||||
|
@ -104,67 +101,6 @@ xt_ct_set_helper(struct nf_conn *ct, const char *helper_name,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int xt_ct_tg_check_v0(const struct xt_tgchk_param *par)
|
|
||||||
{
|
|
||||||
struct xt_ct_target_info *info = par->targinfo;
|
|
||||||
struct nf_conntrack_tuple t;
|
|
||||||
struct nf_conn *ct;
|
|
||||||
int ret = -EOPNOTSUPP;
|
|
||||||
|
|
||||||
if (info->flags & ~XT_CT_NOTRACK)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
if (info->flags & XT_CT_NOTRACK) {
|
|
||||||
ct = nf_ct_untracked_get();
|
|
||||||
atomic_inc(&ct->ct_general.use);
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifndef CONFIG_NF_CONNTRACK_ZONES
|
|
||||||
if (info->zone)
|
|
||||||
goto err1;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
ret = nf_ct_l3proto_try_module_get(par->family);
|
|
||||||
if (ret < 0)
|
|
||||||
goto err1;
|
|
||||||
|
|
||||||
memset(&t, 0, sizeof(t));
|
|
||||||
ct = nf_conntrack_alloc(par->net, info->zone, &t, &t, GFP_KERNEL);
|
|
||||||
ret = PTR_ERR(ct);
|
|
||||||
if (IS_ERR(ct))
|
|
||||||
goto err2;
|
|
||||||
|
|
||||||
ret = 0;
|
|
||||||
if ((info->ct_events || info->exp_events) &&
|
|
||||||
!nf_ct_ecache_ext_add(ct, info->ct_events, info->exp_events,
|
|
||||||
GFP_KERNEL))
|
|
||||||
goto err3;
|
|
||||||
|
|
||||||
if (info->helper[0]) {
|
|
||||||
ret = xt_ct_set_helper(ct, info->helper, par);
|
|
||||||
if (ret < 0)
|
|
||||||
goto err3;
|
|
||||||
}
|
|
||||||
|
|
||||||
__set_bit(IPS_TEMPLATE_BIT, &ct->status);
|
|
||||||
__set_bit(IPS_CONFIRMED_BIT, &ct->status);
|
|
||||||
|
|
||||||
/* Overload tuple linked list to put us in template list. */
|
|
||||||
hlist_nulls_add_head_rcu(&ct->tuplehash[IP_CT_DIR_ORIGINAL].hnnode,
|
|
||||||
&par->net->ct.tmpl);
|
|
||||||
out:
|
|
||||||
info->ct = ct;
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
err3:
|
|
||||||
nf_conntrack_free(ct);
|
|
||||||
err2:
|
|
||||||
nf_ct_l3proto_module_put(par->family);
|
|
||||||
err1:
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef CONFIG_NF_CONNTRACK_TIMEOUT
|
#ifdef CONFIG_NF_CONNTRACK_TIMEOUT
|
||||||
static void __xt_ct_tg_timeout_put(struct ctnl_timeout *timeout)
|
static void __xt_ct_tg_timeout_put(struct ctnl_timeout *timeout)
|
||||||
{
|
{
|
||||||
|
@ -242,16 +178,13 @@ out:
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static int xt_ct_tg_check_v1(const struct xt_tgchk_param *par)
|
static int xt_ct_tg_check(const struct xt_tgchk_param *par,
|
||||||
|
struct xt_ct_target_info_v1 *info)
|
||||||
{
|
{
|
||||||
struct xt_ct_target_info_v1 *info = par->targinfo;
|
|
||||||
struct nf_conntrack_tuple t;
|
struct nf_conntrack_tuple t;
|
||||||
struct nf_conn *ct;
|
struct nf_conn *ct;
|
||||||
int ret = -EOPNOTSUPP;
|
int ret = -EOPNOTSUPP;
|
||||||
|
|
||||||
if (info->flags & ~XT_CT_NOTRACK)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
if (info->flags & XT_CT_NOTRACK) {
|
if (info->flags & XT_CT_NOTRACK) {
|
||||||
ct = nf_ct_untracked_get();
|
ct = nf_ct_untracked_get();
|
||||||
atomic_inc(&ct->ct_general.use);
|
atomic_inc(&ct->ct_general.use);
|
||||||
|
@ -309,20 +242,49 @@ err1:
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void xt_ct_tg_destroy_v0(const struct xt_tgdtor_param *par)
|
static int xt_ct_tg_check_v0(const struct xt_tgchk_param *par)
|
||||||
{
|
{
|
||||||
struct xt_ct_target_info *info = par->targinfo;
|
struct xt_ct_target_info *info = par->targinfo;
|
||||||
struct nf_conn *ct = info->ct;
|
struct xt_ct_target_info_v1 info_v1 = {
|
||||||
struct nf_conn_help *help;
|
.flags = info->flags,
|
||||||
|
.zone = info->zone,
|
||||||
|
.ct_events = info->ct_events,
|
||||||
|
.exp_events = info->exp_events,
|
||||||
|
};
|
||||||
|
int ret;
|
||||||
|
|
||||||
if (!nf_ct_is_untracked(ct)) {
|
if (info->flags & ~XT_CT_NOTRACK)
|
||||||
help = nfct_help(ct);
|
return -EINVAL;
|
||||||
if (help)
|
|
||||||
module_put(help->helper->me);
|
|
||||||
|
|
||||||
nf_ct_l3proto_module_put(par->family);
|
memcpy(info_v1.helper, info->helper, sizeof(info->helper));
|
||||||
}
|
|
||||||
nf_ct_put(info->ct);
|
ret = xt_ct_tg_check(par, &info_v1);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
info->ct = info_v1.ct;
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int xt_ct_tg_check_v1(const struct xt_tgchk_param *par)
|
||||||
|
{
|
||||||
|
struct xt_ct_target_info_v1 *info = par->targinfo;
|
||||||
|
|
||||||
|
if (info->flags & ~XT_CT_NOTRACK)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
return xt_ct_tg_check(par, par->targinfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int xt_ct_tg_check_v2(const struct xt_tgchk_param *par)
|
||||||
|
{
|
||||||
|
struct xt_ct_target_info_v1 *info = par->targinfo;
|
||||||
|
|
||||||
|
if (info->flags & ~XT_CT_MASK)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
return xt_ct_tg_check(par, par->targinfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void xt_ct_destroy_timeout(struct nf_conn *ct)
|
static void xt_ct_destroy_timeout(struct nf_conn *ct)
|
||||||
|
@ -343,9 +305,9 @@ static void xt_ct_destroy_timeout(struct nf_conn *ct)
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static void xt_ct_tg_destroy_v1(const struct xt_tgdtor_param *par)
|
static void xt_ct_tg_destroy(const struct xt_tgdtor_param *par,
|
||||||
|
struct xt_ct_target_info_v1 *info)
|
||||||
{
|
{
|
||||||
struct xt_ct_target_info_v1 *info = par->targinfo;
|
|
||||||
struct nf_conn *ct = info->ct;
|
struct nf_conn *ct = info->ct;
|
||||||
struct nf_conn_help *help;
|
struct nf_conn_help *help;
|
||||||
|
|
||||||
|
@ -361,6 +323,26 @@ static void xt_ct_tg_destroy_v1(const struct xt_tgdtor_param *par)
|
||||||
nf_ct_put(info->ct);
|
nf_ct_put(info->ct);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void xt_ct_tg_destroy_v0(const struct xt_tgdtor_param *par)
|
||||||
|
{
|
||||||
|
struct xt_ct_target_info *info = par->targinfo;
|
||||||
|
struct xt_ct_target_info_v1 info_v1 = {
|
||||||
|
.flags = info->flags,
|
||||||
|
.zone = info->zone,
|
||||||
|
.ct_events = info->ct_events,
|
||||||
|
.exp_events = info->exp_events,
|
||||||
|
.ct = info->ct,
|
||||||
|
};
|
||||||
|
memcpy(info_v1.helper, info->helper, sizeof(info->helper));
|
||||||
|
|
||||||
|
xt_ct_tg_destroy(par, &info_v1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void xt_ct_tg_destroy_v1(const struct xt_tgdtor_param *par)
|
||||||
|
{
|
||||||
|
xt_ct_tg_destroy(par, par->targinfo);
|
||||||
|
}
|
||||||
|
|
||||||
static struct xt_target xt_ct_tg_reg[] __read_mostly = {
|
static struct xt_target xt_ct_tg_reg[] __read_mostly = {
|
||||||
{
|
{
|
||||||
.name = "CT",
|
.name = "CT",
|
||||||
|
@ -383,6 +365,17 @@ static struct xt_target xt_ct_tg_reg[] __read_mostly = {
|
||||||
.table = "raw",
|
.table = "raw",
|
||||||
.me = THIS_MODULE,
|
.me = THIS_MODULE,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
.name = "CT",
|
||||||
|
.family = NFPROTO_UNSPEC,
|
||||||
|
.revision = 2,
|
||||||
|
.targetsize = sizeof(struct xt_ct_target_info_v1),
|
||||||
|
.checkentry = xt_ct_tg_check_v2,
|
||||||
|
.destroy = xt_ct_tg_destroy_v1,
|
||||||
|
.target = xt_ct_target_v1,
|
||||||
|
.table = "raw",
|
||||||
|
.me = THIS_MODULE,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
static unsigned int
|
static unsigned int
|
||||||
|
|
Loading…
Reference in a new issue