Commit 2ccba543 authored by David S. Miller's avatar David S. Miller

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: default avatarDavid S. Miller <davem@davemloft.net>
parents 6338a53a b20ab9cc
...@@ -34,8 +34,8 @@ extern int nfnetlink_send(struct sk_buff *skb, struct net *net, u32 pid, unsigne ...@@ -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 { ...@@ -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 @@ ...@@ -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 { ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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 ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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 ...@@ -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) ...@@ -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) ...@@ -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, ...@@ -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, ...@@ -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 @@ static int help(struct sk_buff *skb, ...@@ -435,8 +435,8 @@ static int help(struct sk_buff *skb,
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 @@ static int help(struct sk_buff *skb, ...@@ -450,6 +450,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;
} }
...@@ -500,9 +501,10 @@ static int help(struct sk_buff *skb, ...@@ -500,9 +501,10 @@ static int help(struct sk_buff *skb,
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, ...@@ -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, ...@@ -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, ...@@ -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 @@ ...@@ -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) ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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 @@ ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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 @@ static unsigned int nf_nat_sip(struct sk_buff *skb, unsigned int protoff, ...@@ -253,27 +262,35 @@ static unsigned int nf_nat_sip(struct sk_buff *skb, unsigned int protoff,
&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, ...@@ -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, ...@@ -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, ...@@ -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); ...@@ -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] = { ...@@ -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); ...@@ -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 ...@@ -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 @@ static int nfnetlink_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) ...@@ -175,6 +182,7 @@ static int nfnetlink_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
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 @@ static int nfnetlink_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) ...@@ -189,10 +197,9 @@ static int nfnetlink_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
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 @@ static int nfnetlink_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) ...@@ -200,7 +207,7 @@ static int nfnetlink_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
(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 = { ...@@ -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 @@ ...@@ -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, ...@@ -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_v1(struct sk_buff *skb, static unsigned int xt_ct_target_v0(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 *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); static unsigned int xt_ct_target_v1(struct sk_buff *skb,
skb->nfct = &ct->ct_general; const struct xt_action_param *par)
skb->nfctinfo = IP_CT_NEW; {
const struct xt_ct_target_info_v1 *info = par->targinfo;
struct nf_conn *ct = info->ct;
return XT_CONTINUE; return xt_ct_target(skb, ct);
} }
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, ...@@ -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 @@ xt_ct_set_timeout(struct nf_conn *ct, const struct xt_tgchk_param *par, ...@@ -242,16 +178,13 @@ xt_ct_set_timeout(struct nf_conn *ct, const struct xt_tgchk_param *par,
#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 @@ static int xt_ct_tg_check_v1(const struct xt_tgchk_param *par) ...@@ -309,20 +242,49 @@ static int xt_ct_tg_check_v1(const struct xt_tgchk_param *par)
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) ...@@ -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) ...@@ -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 = { ...@@ -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
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment