* [NETFILTER 01/32]: ipt_CLUSTERIP: fix non-existant macro-name
2008-03-25 14:14 [METFILTER 00/32]: SIP helper update Patrick McHardy
@ 2008-03-25 14:14 ` Patrick McHardy
2008-03-25 14:14 ` [NETFILTER 02/32]: nf_conntrack: fix NF_CT_TUPLE_DUMP for IPv4 Patrick McHardy
` (31 subsequent siblings)
32 siblings, 0 replies; 39+ messages in thread
From: Patrick McHardy @ 2008-03-25 14:14 UTC (permalink / raw)
To: davem; +Cc: Patrick McHardy, netfilter-devel
[NETFILTER]: ipt_CLUSTERIP: fix non-existant macro-name
With nf_conntrack DUMP_TUPLE got renamed to NF_CT_DUMP_TUPLE, fix
CLUSTERIP to use the proper macro name.
Signed-off-by: Patrick McHardy <kaber@trash.net>
---
commit 9f6e380c98a01aa41754fa04ae5b11a11987a69a
tree 42c74ac2a2fe17df5cc61c734bb0462804d35c8c
parent 7cbca67c073263c179f605bdbbdc565ab29d801d
author Patrick McHardy <kaber@trash.net> Tue, 25 Mar 2008 13:44:35 +0100
committer Patrick McHardy <kaber@trash.net> Tue, 25 Mar 2008 13:44:35 +0100
net/ipv4/netfilter/ipt_CLUSTERIP.c | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/net/ipv4/netfilter/ipt_CLUSTERIP.c b/net/ipv4/netfilter/ipt_CLUSTERIP.c
index c6cf84c..1b10f36 100644
--- a/net/ipv4/netfilter/ipt_CLUSTERIP.c
+++ b/net/ipv4/netfilter/ipt_CLUSTERIP.c
@@ -332,7 +332,7 @@ clusterip_tg(struct sk_buff *skb, const struct net_device *in,
}
#ifdef DEBUG
- DUMP_TUPLE(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple);
+ NF_CT_DUMP_TUPLE(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple);
#endif
pr_debug("hash=%u ct_hash=%u ", hash, ct->mark);
if (!clusterip_responsible(cipinfo->config, hash)) {
^ permalink raw reply related [flat|nested] 39+ messages in thread* [NETFILTER 02/32]: nf_conntrack: fix NF_CT_TUPLE_DUMP for IPv4
2008-03-25 14:14 [METFILTER 00/32]: SIP helper update Patrick McHardy
2008-03-25 14:14 ` [NETFILTER 01/32]: ipt_CLUSTERIP: fix non-existant macro-name Patrick McHardy
@ 2008-03-25 14:14 ` Patrick McHardy
2008-03-25 15:26 ` Jan Engelhardt
2008-03-25 14:14 ` [NETFILTER 03/32]: nf_conntrack_expect: constify nf_ct_expect_init arguments Patrick McHardy
` (30 subsequent siblings)
32 siblings, 1 reply; 39+ messages in thread
From: Patrick McHardy @ 2008-03-25 14:14 UTC (permalink / raw)
To: davem; +Cc: Patrick McHardy, netfilter-devel
[NETFILTER]: nf_conntrack: fix NF_CT_TUPLE_DUMP for IPv4
NF_CT_TUPLE_DUMP prints IPv4 addresses as IPv6, fix this and use printk
(guarded by #ifdef DEBUG) directly instead of pr_debug since the tuple
is usually printed at the end of line and we don't want to include a
log-level.
Signed-off-by: Patrick McHardy <kaber@trash.net>
---
commit 80c9efadd8bc6e868922106b37742c8ab70ea804
tree 8300964a0ff77ca48ae85bec539a2231c7a89a31
parent 9f6e380c98a01aa41754fa04ae5b11a11987a69a
author Patrick McHardy <kaber@trash.net> Tue, 25 Mar 2008 13:44:36 +0100
committer Patrick McHardy <kaber@trash.net> Tue, 25 Mar 2008 13:44:36 +0100
include/net/netfilter/nf_conntrack_tuple.h | 38 ++++++++++++++++++++++++----
1 files changed, 33 insertions(+), 5 deletions(-)
diff --git a/include/net/netfilter/nf_conntrack_tuple.h b/include/net/netfilter/nf_conntrack_tuple.h
index e69ab2e..d9b53dd 100644
--- a/include/net/netfilter/nf_conntrack_tuple.h
+++ b/include/net/netfilter/nf_conntrack_tuple.h
@@ -113,11 +113,39 @@ struct nf_conntrack_tuple_mask
#ifdef __KERNEL__
-#define NF_CT_DUMP_TUPLE(tp) \
-pr_debug("tuple %p: %u %u " NIP6_FMT " %hu -> " NIP6_FMT " %hu\n", \
- (tp), (tp)->src.l3num, (tp)->dst.protonum, \
- NIP6(*(struct in6_addr *)(tp)->src.u3.all), ntohs((tp)->src.u.all), \
- NIP6(*(struct in6_addr *)(tp)->dst.u3.all), ntohs((tp)->dst.u.all))
+static inline void nf_ct_dump_tuple_ip(const struct nf_conntrack_tuple *t)
+{
+#ifdef DEBUG
+ printk("tuple %p: %u " NIPQUAD_FMT ":%hu -> " NIPQUAD_FMT ":%hu\n",
+ t, t->dst.protonum,
+ NIPQUAD(t->src.u3.ip), ntohs(t->src.u.all),
+ NIPQUAD(t->dst.u3.ip), ntohs(t->dst.u.all));
+#endif
+}
+
+static inline void nf_ct_dump_tuple_ipv6(const struct nf_conntrack_tuple *t)
+{
+#ifdef DEBUG
+ printk("tuple %p: %u " NIP6_FMT " %hu -> " NIP6_FMT " %hu\n",
+ t, t->dst.protonum,
+ NIP6(*(struct in6_addr *)t->src.u3.all), ntohs(t->src.u.all),
+ NIP6(*(struct in6_addr *)t->dst.u3.all), ntohs(t->dst.u.all));
+#endif
+}
+
+static inline void nf_ct_dump_tuple(const struct nf_conntrack_tuple *t)
+{
+ switch (t->src.l3num) {
+ case AF_INET:
+ nf_ct_dump_tuple_ip(t);
+ break;
+ case AF_INET6:
+ nf_ct_dump_tuple_ipv6(t);
+ break;
+ }
+}
+
+#define NF_CT_DUMP_TUPLE(tp) nf_ct_dump_tuple(tp)
/* If we're the first tuple, it's the original dir. */
#define NF_CT_DIRECTION(h) \
^ permalink raw reply related [flat|nested] 39+ messages in thread* Re: [NETFILTER 02/32]: nf_conntrack: fix NF_CT_TUPLE_DUMP for IPv4
2008-03-25 14:14 ` [NETFILTER 02/32]: nf_conntrack: fix NF_CT_TUPLE_DUMP for IPv4 Patrick McHardy
@ 2008-03-25 15:26 ` Jan Engelhardt
2008-03-25 15:31 ` Patrick McHardy
0 siblings, 1 reply; 39+ messages in thread
From: Jan Engelhardt @ 2008-03-25 15:26 UTC (permalink / raw)
To: Patrick McHardy; +Cc: davem, netfilter-devel
On Tuesday 2008-03-25 15:14, Patrick McHardy wrote:
> +
> +static inline void nf_ct_dump_tuple(const struct nf_conntrack_tuple *t)
> +{
> + switch (t->src.l3num) {
> + case AF_INET:
> + nf_ct_dump_tuple_ip(t);
> + break;
> + case AF_INET6:
> + nf_ct_dump_tuple_ipv6(t);
> + break;
> + }
> +}
> +
> +#define NF_CT_DUMP_TUPLE(tp) nf_ct_dump_tuple(tp)
I think it would be wiser just to remove this macro and
convert all kernel users to lowercase -- there are only
kernel users I guess, since include/net/ is not exported
to userspace AFAICS.
^ permalink raw reply [flat|nested] 39+ messages in thread* Re: [NETFILTER 02/32]: nf_conntrack: fix NF_CT_TUPLE_DUMP for IPv4
2008-03-25 15:26 ` Jan Engelhardt
@ 2008-03-25 15:31 ` Patrick McHardy
0 siblings, 0 replies; 39+ messages in thread
From: Patrick McHardy @ 2008-03-25 15:31 UTC (permalink / raw)
To: Jan Engelhardt; +Cc: davem, netfilter-devel
Jan Engelhardt wrote:
>
> On Tuesday 2008-03-25 15:14, Patrick McHardy wrote:
>> +
>> +static inline void nf_ct_dump_tuple(const struct nf_conntrack_tuple *t)
>> +{
>> + switch (t->src.l3num) {
>> + case AF_INET:
>> + nf_ct_dump_tuple_ip(t);
>> + break;
>> + case AF_INET6:
>> + nf_ct_dump_tuple_ipv6(t);
>> + break;
>> + }
>> +}
>> +
>> +#define NF_CT_DUMP_TUPLE(tp) nf_ct_dump_tuple(tp)
>
> I think it would be wiser just to remove this macro and
> convert all kernel users to lowercase -- there are only
> kernel users I guess, since include/net/ is not exported
> to userspace AFAICS.
>
Sure, please go ahead :)
^ permalink raw reply [flat|nested] 39+ messages in thread
* [NETFILTER 03/32]: nf_conntrack_expect: constify nf_ct_expect_init arguments
2008-03-25 14:14 [METFILTER 00/32]: SIP helper update Patrick McHardy
2008-03-25 14:14 ` [NETFILTER 01/32]: ipt_CLUSTERIP: fix non-existant macro-name Patrick McHardy
2008-03-25 14:14 ` [NETFILTER 02/32]: nf_conntrack: fix NF_CT_TUPLE_DUMP for IPv4 Patrick McHardy
@ 2008-03-25 14:14 ` Patrick McHardy
2008-03-25 14:14 ` [NETFILTER 04/32]: nf_conntrack_expect: show NF_CT_EXPECT_PERMANENT flag in /proc Patrick McHardy
` (29 subsequent siblings)
32 siblings, 0 replies; 39+ messages in thread
From: Patrick McHardy @ 2008-03-25 14:14 UTC (permalink / raw)
To: davem; +Cc: Patrick McHardy, netfilter-devel
[NETFILTER]: nf_conntrack_expect: constify nf_ct_expect_init arguments
Signed-off-by: Patrick McHardy <kaber@trash.net>
---
commit ee8406f54b255b347c08802fb39c13c2865234dc
tree 1de164bc0d51b676aad5b317050664b9b4b504f6
parent 80c9efadd8bc6e868922106b37742c8ab70ea804
author Patrick McHardy <kaber@trash.net> Tue, 25 Mar 2008 13:44:38 +0100
committer Patrick McHardy <kaber@trash.net> Tue, 25 Mar 2008 13:44:38 +0100
include/net/netfilter/nf_conntrack_expect.h | 6 +++---
net/netfilter/nf_conntrack_expect.c | 6 +++---
2 files changed, 6 insertions(+), 6 deletions(-)
diff --git a/include/net/netfilter/nf_conntrack_expect.h b/include/net/netfilter/nf_conntrack_expect.h
index cb608a1..f1bdcb4 100644
--- a/include/net/netfilter/nf_conntrack_expect.h
+++ b/include/net/netfilter/nf_conntrack_expect.h
@@ -75,9 +75,9 @@ void nf_ct_unexpect_related(struct nf_conntrack_expect *exp);
nf_ct_expect_related. You will have to call put afterwards. */
struct nf_conntrack_expect *nf_ct_expect_alloc(struct nf_conn *me);
void nf_ct_expect_init(struct nf_conntrack_expect *, int,
- union nf_inet_addr *,
- union nf_inet_addr *,
- u_int8_t, __be16 *, __be16 *);
+ const union nf_inet_addr *,
+ const union nf_inet_addr *,
+ u_int8_t, const __be16 *, const __be16 *);
void nf_ct_expect_put(struct nf_conntrack_expect *exp);
int nf_ct_expect_related(struct nf_conntrack_expect *expect);
diff --git a/net/netfilter/nf_conntrack_expect.c b/net/netfilter/nf_conntrack_expect.c
index 684ec9c..740d94d 100644
--- a/net/netfilter/nf_conntrack_expect.c
+++ b/net/netfilter/nf_conntrack_expect.c
@@ -229,9 +229,9 @@ struct nf_conntrack_expect *nf_ct_expect_alloc(struct nf_conn *me)
EXPORT_SYMBOL_GPL(nf_ct_expect_alloc);
void nf_ct_expect_init(struct nf_conntrack_expect *exp, int family,
- union nf_inet_addr *saddr,
- union nf_inet_addr *daddr,
- u_int8_t proto, __be16 *src, __be16 *dst)
+ const union nf_inet_addr *saddr,
+ const union nf_inet_addr *daddr,
+ u_int8_t proto, const __be16 *src, const __be16 *dst)
{
int len;
^ permalink raw reply related [flat|nested] 39+ messages in thread* [NETFILTER 04/32]: nf_conntrack_expect: show NF_CT_EXPECT_PERMANENT flag in /proc
2008-03-25 14:14 [METFILTER 00/32]: SIP helper update Patrick McHardy
` (2 preceding siblings ...)
2008-03-25 14:14 ` [NETFILTER 03/32]: nf_conntrack_expect: constify nf_ct_expect_init arguments Patrick McHardy
@ 2008-03-25 14:14 ` Patrick McHardy
2008-03-25 14:14 ` [NETFILTER 05/32]: nf_conntrack_expect: support inactive expectations Patrick McHardy
` (28 subsequent siblings)
32 siblings, 0 replies; 39+ messages in thread
From: Patrick McHardy @ 2008-03-25 14:14 UTC (permalink / raw)
To: davem; +Cc: Patrick McHardy, netfilter-devel
[NETFILTER]: nf_conntrack_expect: show NF_CT_EXPECT_PERMANENT flag in /proc
Signed-off-by: Patrick McHardy <kaber@trash.net>
---
commit c17414dd75203d003a75a024de4ad736a64bc3e5
tree 061681c3626d0d535020efecbb578080883820a9
parent ee8406f54b255b347c08802fb39c13c2865234dc
author Patrick McHardy <kaber@trash.net> Tue, 25 Mar 2008 13:44:39 +0100
committer Patrick McHardy <kaber@trash.net> Tue, 25 Mar 2008 13:44:39 +0100
net/netfilter/nf_conntrack_expect.c | 4 ++++
1 files changed, 4 insertions(+), 0 deletions(-)
diff --git a/net/netfilter/nf_conntrack_expect.c b/net/netfilter/nf_conntrack_expect.c
index 740d94d..4c05a58 100644
--- a/net/netfilter/nf_conntrack_expect.c
+++ b/net/netfilter/nf_conntrack_expect.c
@@ -475,6 +475,10 @@ static int exp_seq_show(struct seq_file *s, void *v)
__nf_ct_l3proto_find(expect->tuple.src.l3num),
__nf_ct_l4proto_find(expect->tuple.src.l3num,
expect->tuple.dst.protonum));
+
+ if (expect->flags & NF_CT_EXPECT_PERMANENT)
+ seq_printf(s, "PERMANENT ");
+
return seq_putc(s, '\n');
}
^ permalink raw reply related [flat|nested] 39+ messages in thread* [NETFILTER 05/32]: nf_conntrack_expect: support inactive expectations
2008-03-25 14:14 [METFILTER 00/32]: SIP helper update Patrick McHardy
` (3 preceding siblings ...)
2008-03-25 14:14 ` [NETFILTER 04/32]: nf_conntrack_expect: show NF_CT_EXPECT_PERMANENT flag in /proc Patrick McHardy
@ 2008-03-25 14:14 ` Patrick McHardy
2008-03-25 14:14 ` [NETFILTER 06/32]: nf_conntrack: introduce expectation classes and policies Patrick McHardy
` (27 subsequent siblings)
32 siblings, 0 replies; 39+ messages in thread
From: Patrick McHardy @ 2008-03-25 14:14 UTC (permalink / raw)
To: davem; +Cc: Patrick McHardy, netfilter-devel
[NETFILTER]: nf_conntrack_expect: support inactive expectations
This is useful for the SIP helper and signalling expectations.
We don't want to create a full-blown expectation with a wildcard
as source based on a single UDP packet, but need to know the
final port anyways. With inactive expectations we can register
the expectation and reserve the tuple, but wait for confirmation
from the registrar before activating it.
Signed-off-by: Patrick McHardy <kaber@trash.net>
---
commit da5c5564d2082bff6fe8e9cc5e4df3ffdac1887d
tree 72922ee7ea0a6913c61d7f5f555be77e727cfb7c
parent c17414dd75203d003a75a024de4ad736a64bc3e5
author Patrick McHardy <kaber@trash.net> Tue, 25 Mar 2008 13:44:41 +0100
committer Patrick McHardy <kaber@trash.net> Tue, 25 Mar 2008 13:44:41 +0100
include/net/netfilter/nf_conntrack_expect.h | 3 ++-
net/netfilter/nf_conntrack_expect.c | 25 +++++++++++++++++++++----
2 files changed, 23 insertions(+), 5 deletions(-)
diff --git a/include/net/netfilter/nf_conntrack_expect.h b/include/net/netfilter/nf_conntrack_expect.h
index f1bdcb4..47c28dd 100644
--- a/include/net/netfilter/nf_conntrack_expect.h
+++ b/include/net/netfilter/nf_conntrack_expect.h
@@ -53,7 +53,8 @@ struct nf_conntrack_expect
struct rcu_head rcu;
};
-#define NF_CT_EXPECT_PERMANENT 0x1
+#define NF_CT_EXPECT_PERMANENT 0x1
+#define NF_CT_EXPECT_INACTIVE 0x2
int nf_conntrack_expect_init(void);
void nf_conntrack_expect_fini(void);
diff --git a/net/netfilter/nf_conntrack_expect.c b/net/netfilter/nf_conntrack_expect.c
index 4c05a58..882602f 100644
--- a/net/netfilter/nf_conntrack_expect.c
+++ b/net/netfilter/nf_conntrack_expect.c
@@ -126,9 +126,21 @@ EXPORT_SYMBOL_GPL(nf_ct_expect_find_get);
struct nf_conntrack_expect *
nf_ct_find_expectation(const struct nf_conntrack_tuple *tuple)
{
- struct nf_conntrack_expect *exp;
+ struct nf_conntrack_expect *i, *exp = NULL;
+ struct hlist_node *n;
+ unsigned int h;
+
+ if (!nf_ct_expect_count)
+ return NULL;
- exp = __nf_ct_expect_find(tuple);
+ h = nf_ct_expect_dst_hash(tuple);
+ hlist_for_each_entry(i, n, &nf_ct_expect_hash[h], hnode) {
+ if (!(i->flags & NF_CT_EXPECT_INACTIVE) &&
+ nf_ct_tuple_mask_cmp(tuple, &i->tuple, &i->mask)) {
+ exp = i;
+ break;
+ }
+ }
if (!exp)
return NULL;
@@ -460,6 +472,7 @@ static int exp_seq_show(struct seq_file *s, void *v)
{
struct nf_conntrack_expect *expect;
struct hlist_node *n = v;
+ char *delim = "";
expect = hlist_entry(n, struct nf_conntrack_expect, hnode);
@@ -476,8 +489,12 @@ static int exp_seq_show(struct seq_file *s, void *v)
__nf_ct_l4proto_find(expect->tuple.src.l3num,
expect->tuple.dst.protonum));
- if (expect->flags & NF_CT_EXPECT_PERMANENT)
- seq_printf(s, "PERMANENT ");
+ if (expect->flags & NF_CT_EXPECT_PERMANENT) {
+ seq_printf(s, "PERMANENT");
+ delim = ",";
+ }
+ if (expect->flags & NF_CT_EXPECT_INACTIVE)
+ seq_printf(s, "%sINACTIVE", delim);
return seq_putc(s, '\n');
}
^ permalink raw reply related [flat|nested] 39+ messages in thread* [NETFILTER 06/32]: nf_conntrack: introduce expectation classes and policies
2008-03-25 14:14 [METFILTER 00/32]: SIP helper update Patrick McHardy
` (4 preceding siblings ...)
2008-03-25 14:14 ` [NETFILTER 05/32]: nf_conntrack_expect: support inactive expectations Patrick McHardy
@ 2008-03-25 14:14 ` Patrick McHardy
2008-03-25 15:46 ` Jan Engelhardt
2008-03-25 14:15 ` [NETFILTER 07/32]: Add nf_inet_addr_cmp() Patrick McHardy
` (26 subsequent siblings)
32 siblings, 1 reply; 39+ messages in thread
From: Patrick McHardy @ 2008-03-25 14:14 UTC (permalink / raw)
To: davem; +Cc: Patrick McHardy, netfilter-devel
[NETFILTER]: nf_conntrack: introduce expectation classes and policies
Introduce expectation classes and policies. An expectation class
is used to distinguish different types of expectations by the
same helper (for example audio/video/t.120). The expectation
policy is used to hold the maximum number of expectations and
the initial timeout for each class.
The individual classes are isolated from each other, which means
that for example an audio expectation will only evict other audio
expectations.
Signed-off-by: Patrick McHardy <kaber@trash.net>
---
commit 48bb8ab5591cab986a2850facf33998357db3b10
tree 11145198c9ca2ef44dbb2898a2cd9e18a56b17c2
parent da5c5564d2082bff6fe8e9cc5e4df3ffdac1887d
author Patrick McHardy <kaber@trash.net> Tue, 25 Mar 2008 13:44:43 +0100
committer Patrick McHardy <kaber@trash.net> Tue, 25 Mar 2008 13:44:43 +0100
include/net/netfilter/nf_conntrack.h | 5 ++
include/net/netfilter/nf_conntrack_expect.h | 13 +++++
include/net/netfilter/nf_conntrack_helper.h | 5 +-
net/ipv4/netfilter/nf_nat_snmp_basic.c | 12 +++--
net/netfilter/nf_conntrack_amanda.c | 14 ++++--
net/netfilter/nf_conntrack_expect.c | 50 ++++++++++++++------
net/netfilter/nf_conntrack_ftp.c | 10 +++-
net/netfilter/nf_conntrack_h323_main.c | 66 +++++++++++++++++----------
net/netfilter/nf_conntrack_helper.c | 3 +
net/netfilter/nf_conntrack_irc.c | 10 +++-
net/netfilter/nf_conntrack_netbios_ns.c | 9 +++-
net/netfilter/nf_conntrack_pptp.c | 14 ++++--
net/netfilter/nf_conntrack_sane.c | 11 +++--
net/netfilter/nf_conntrack_sip.c | 10 +++-
net/netfilter/nf_conntrack_tftp.c | 11 +++--
15 files changed, 166 insertions(+), 77 deletions(-)
diff --git a/include/net/netfilter/nf_conntrack.h b/include/net/netfilter/nf_conntrack.h
index 90b3e7f..9228771 100644
--- a/include/net/netfilter/nf_conntrack.h
+++ b/include/net/netfilter/nf_conntrack.h
@@ -75,6 +75,9 @@ do { \
struct nf_conntrack_helper;
+/* Must be kept in sync with the classes defined by helpers */
+#define NF_CT_MAX_EXPECT_CLASSES 1
+
/* nf_conn feature for connections that have a helper */
struct nf_conn_help {
/* Helper. if any */
@@ -85,7 +88,7 @@ struct nf_conn_help {
struct hlist_head expectations;
/* Current number of expected connections */
- unsigned int expecting;
+ u8 expecting[NF_CT_MAX_EXPECT_CLASSES];
};
diff --git a/include/net/netfilter/nf_conntrack_expect.h b/include/net/netfilter/nf_conntrack_expect.h
index 47c28dd..dfdf4b4 100644
--- a/include/net/netfilter/nf_conntrack_expect.h
+++ b/include/net/netfilter/nf_conntrack_expect.h
@@ -41,6 +41,9 @@ struct nf_conntrack_expect
/* Flags */
unsigned int flags;
+ /* Expectation class */
+ unsigned int class;
+
#ifdef CONFIG_NF_NAT_NEEDED
__be32 saved_ip;
/* This is the original per-proto part, used to map the
@@ -53,6 +56,14 @@ struct nf_conntrack_expect
struct rcu_head rcu;
};
+struct nf_conntrack_expect_policy
+{
+ unsigned int max_expected;
+ unsigned int timeout;
+};
+
+#define NF_CT_EXPECT_CLASS_DEFAULT 0
+
#define NF_CT_EXPECT_PERMANENT 0x1
#define NF_CT_EXPECT_INACTIVE 0x2
@@ -75,7 +86,7 @@ void nf_ct_unexpect_related(struct nf_conntrack_expect *exp);
/* Allocate space for an expectation: this is mandatory before calling
nf_ct_expect_related. You will have to call put afterwards. */
struct nf_conntrack_expect *nf_ct_expect_alloc(struct nf_conn *me);
-void nf_ct_expect_init(struct nf_conntrack_expect *, int,
+void nf_ct_expect_init(struct nf_conntrack_expect *, unsigned int, int,
const union nf_inet_addr *,
const union nf_inet_addr *,
u_int8_t, const __be16 *, const __be16 *);
diff --git a/include/net/netfilter/nf_conntrack_helper.h b/include/net/netfilter/nf_conntrack_helper.h
index 4ca125e..f8060ab 100644
--- a/include/net/netfilter/nf_conntrack_helper.h
+++ b/include/net/netfilter/nf_conntrack_helper.h
@@ -20,9 +20,7 @@ struct nf_conntrack_helper
const char *name; /* name of the module */
struct module *me; /* pointer to self */
- unsigned int max_expected; /* Maximum number of concurrent
- * expected connections */
- unsigned int timeout; /* timeout for expecteds */
+ const struct nf_conntrack_expect_policy *expect_policy;
/* Tuple of things we will help (compared against server response) */
struct nf_conntrack_tuple tuple;
@@ -37,6 +35,7 @@ struct nf_conntrack_helper
void (*destroy)(struct nf_conn *ct);
int (*to_nlattr)(struct sk_buff *skb, const struct nf_conn *ct);
+ unsigned int expect_class_max;
};
extern struct nf_conntrack_helper *
diff --git a/net/ipv4/netfilter/nf_nat_snmp_basic.c b/net/ipv4/netfilter/nf_nat_snmp_basic.c
index 540ce6a..000e080 100644
--- a/net/ipv4/netfilter/nf_nat_snmp_basic.c
+++ b/net/ipv4/netfilter/nf_nat_snmp_basic.c
@@ -50,6 +50,7 @@
#include <net/udp.h>
#include <net/netfilter/nf_nat.h>
+#include <net/netfilter/nf_conntrack_expect.h>
#include <net/netfilter/nf_conntrack_helper.h>
#include <net/netfilter/nf_nat_helper.h>
@@ -1267,11 +1268,15 @@ static int help(struct sk_buff *skb, unsigned int protoff,
return ret;
}
+static const struct nf_conntrack_expect_policy snmp_exp_policy = {
+ .max_expected = 0,
+ .timeout = 180,
+};
+
static struct nf_conntrack_helper snmp_helper __read_mostly = {
- .max_expected = 0,
- .timeout = 180,
.me = THIS_MODULE,
.help = help,
+ .expect_policy = &snmp_exp_policy,
.name = "snmp",
.tuple.src.l3num = AF_INET,
.tuple.src.u.udp.port = __constant_htons(SNMP_PORT),
@@ -1279,10 +1284,9 @@ static struct nf_conntrack_helper snmp_helper __read_mostly = {
};
static struct nf_conntrack_helper snmp_trap_helper __read_mostly = {
- .max_expected = 0,
- .timeout = 180,
.me = THIS_MODULE,
.help = help,
+ .expect_policy = &snmp_exp_policy,
.name = "snmp_trap",
.tuple.src.l3num = AF_INET,
.tuple.src.u.udp.port = __constant_htons(SNMP_TRAP_PORT),
diff --git a/net/netfilter/nf_conntrack_amanda.c b/net/netfilter/nf_conntrack_amanda.c
index 7b8239c..d14585a 100644
--- a/net/netfilter/nf_conntrack_amanda.c
+++ b/net/netfilter/nf_conntrack_amanda.c
@@ -148,7 +148,8 @@ static int amanda_help(struct sk_buff *skb,
goto out;
}
tuple = &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple;
- nf_ct_expect_init(exp, family, &tuple->src.u3, &tuple->dst.u3,
+ nf_ct_expect_init(exp, NF_CT_EXPECT_CLASS_DEFAULT, family,
+ &tuple->src.u3, &tuple->dst.u3,
IPPROTO_TCP, NULL, &port);
nf_nat_amanda = rcu_dereference(nf_nat_amanda_hook);
@@ -164,26 +165,29 @@ out:
return ret;
}
+static const struct nf_conntrack_expect_policy amanda_exp_policy = {
+ .max_expected = 3,
+ .timeout = 180,
+};
+
static struct nf_conntrack_helper amanda_helper[2] __read_mostly = {
{
.name = "amanda",
- .max_expected = 3,
- .timeout = 180,
.me = THIS_MODULE,
.help = amanda_help,
.tuple.src.l3num = AF_INET,
.tuple.src.u.udp.port = __constant_htons(10080),
.tuple.dst.protonum = IPPROTO_UDP,
+ .expect_policy = &amanda_exp_policy,
},
{
.name = "amanda",
- .max_expected = 3,
- .timeout = 180,
.me = THIS_MODULE,
.help = amanda_help,
.tuple.src.l3num = AF_INET6,
.tuple.src.u.udp.port = __constant_htons(10080),
.tuple.dst.protonum = IPPROTO_UDP,
+ .expect_policy = &amanda_exp_policy,
},
};
diff --git a/net/netfilter/nf_conntrack_expect.c b/net/netfilter/nf_conntrack_expect.c
index 882602f..e31beeb 100644
--- a/net/netfilter/nf_conntrack_expect.c
+++ b/net/netfilter/nf_conntrack_expect.c
@@ -54,7 +54,7 @@ void nf_ct_unlink_expect(struct nf_conntrack_expect *exp)
nf_ct_expect_count--;
hlist_del(&exp->lnode);
- master_help->expecting--;
+ master_help->expecting[exp->class]--;
nf_ct_expect_put(exp);
NF_CT_STAT_INC(expect_delete);
@@ -171,7 +171,7 @@ void nf_ct_remove_expectations(struct nf_conn *ct)
struct hlist_node *n, *next;
/* Optimization: most connection never expect any others. */
- if (!help || help->expecting == 0)
+ if (!help)
return;
hlist_for_each_entry_safe(exp, n, next, &help->expectations, lnode) {
@@ -205,7 +205,7 @@ static inline int expect_clash(const struct nf_conntrack_expect *a,
static inline int expect_matches(const struct nf_conntrack_expect *a,
const struct nf_conntrack_expect *b)
{
- return a->master == b->master
+ return a->master == b->master && a->class == b->class
&& nf_ct_tuple_equal(&a->tuple, &b->tuple)
&& nf_ct_tuple_mask_equal(&a->mask, &b->mask);
}
@@ -240,7 +240,8 @@ struct nf_conntrack_expect *nf_ct_expect_alloc(struct nf_conn *me)
}
EXPORT_SYMBOL_GPL(nf_ct_expect_alloc);
-void nf_ct_expect_init(struct nf_conntrack_expect *exp, int family,
+void nf_ct_expect_init(struct nf_conntrack_expect *exp, unsigned int class,
+ int family,
const union nf_inet_addr *saddr,
const union nf_inet_addr *daddr,
u_int8_t proto, const __be16 *src, const __be16 *dst)
@@ -253,6 +254,7 @@ void nf_ct_expect_init(struct nf_conntrack_expect *exp, int family,
len = 16;
exp->flags = 0;
+ exp->class = class;
exp->expectfn = NULL;
exp->helper = NULL;
exp->tuple.src.l3num = family;
@@ -309,19 +311,21 @@ EXPORT_SYMBOL_GPL(nf_ct_expect_put);
static void nf_ct_expect_insert(struct nf_conntrack_expect *exp)
{
struct nf_conn_help *master_help = nfct_help(exp->master);
+ const struct nf_conntrack_expect_policy *p;
unsigned int h = nf_ct_expect_dst_hash(&exp->tuple);
atomic_inc(&exp->use);
hlist_add_head(&exp->lnode, &master_help->expectations);
- master_help->expecting++;
+ master_help->expecting[exp->class]++;
hlist_add_head_rcu(&exp->hnode, &nf_ct_expect_hash[h]);
nf_ct_expect_count++;
setup_timer(&exp->timeout, nf_ct_expectation_timed_out,
(unsigned long)exp);
- exp->timeout.expires = jiffies + master_help->helper->timeout * HZ;
+ p = &master_help->helper->expect_policy[exp->class];
+ exp->timeout.expires = jiffies + p->timeout * HZ;
add_timer(&exp->timeout);
atomic_inc(&exp->use);
@@ -329,35 +333,41 @@ static void nf_ct_expect_insert(struct nf_conntrack_expect *exp)
}
/* Race with expectations being used means we could have none to find; OK. */
-static void evict_oldest_expect(struct nf_conn *master)
+static void evict_oldest_expect(struct nf_conn *master,
+ struct nf_conntrack_expect *new)
{
struct nf_conn_help *master_help = nfct_help(master);
- struct nf_conntrack_expect *exp = NULL;
+ struct nf_conntrack_expect *exp, *last = NULL;
struct hlist_node *n;
- hlist_for_each_entry(exp, n, &master_help->expectations, lnode)
- ; /* nothing */
+ hlist_for_each_entry(exp, n, &master_help->expectations, lnode) {
+ if (exp->class == new->class)
+ last = exp;
+ }
- if (exp && del_timer(&exp->timeout)) {
- nf_ct_unlink_expect(exp);
- nf_ct_expect_put(exp);
+ if (last && del_timer(&last->timeout)) {
+ nf_ct_unlink_expect(last);
+ nf_ct_expect_put(last);
}
}
static inline int refresh_timer(struct nf_conntrack_expect *i)
{
struct nf_conn_help *master_help = nfct_help(i->master);
+ const struct nf_conntrack_expect_policy *p;
if (!del_timer(&i->timeout))
return 0;
- i->timeout.expires = jiffies + master_help->helper->timeout*HZ;
+ p = &master_help->helper->expect_policy[i->class];
+ i->timeout.expires = jiffies + p->timeout * HZ;
add_timer(&i->timeout);
return 1;
}
int nf_ct_expect_related(struct nf_conntrack_expect *expect)
{
+ const struct nf_conntrack_expect_policy *p;
struct nf_conntrack_expect *i;
struct nf_conn *master = expect->master;
struct nf_conn_help *master_help = nfct_help(master);
@@ -386,9 +396,15 @@ int nf_ct_expect_related(struct nf_conntrack_expect *expect)
}
}
/* Will be over limit? */
- if (master_help->helper->max_expected &&
- master_help->expecting >= master_help->helper->max_expected)
- evict_oldest_expect(master);
+ p = &master_help->helper->expect_policy[expect->class];
+ if (p->max_expected &&
+ master_help->expecting[expect->class] >= p->max_expected) {
+ evict_oldest_expect(master, expect);
+ if (master_help->expecting[expect->class] >= p->max_expected) {
+ ret = -EMFILE;
+ goto out;
+ }
+ }
if (nf_ct_expect_count >= nf_ct_expect_max) {
if (net_ratelimit())
diff --git a/net/netfilter/nf_conntrack_ftp.c b/net/netfilter/nf_conntrack_ftp.c
index 6770baf..7eff876 100644
--- a/net/netfilter/nf_conntrack_ftp.c
+++ b/net/netfilter/nf_conntrack_ftp.c
@@ -483,7 +483,7 @@ static int help(struct sk_buff *skb,
daddr = &cmd.u3;
}
- nf_ct_expect_init(exp, cmd.l3num,
+ nf_ct_expect_init(exp, NF_CT_EXPECT_CLASS_DEFAULT, cmd.l3num,
&ct->tuplehash[!dir].tuple.src.u3, daddr,
IPPROTO_TCP, NULL, &cmd.u.tcp.port);
@@ -517,6 +517,11 @@ out_update_nl:
static struct nf_conntrack_helper ftp[MAX_PORTS][2] __read_mostly;
static char ftp_names[MAX_PORTS][2][sizeof("ftp-65535")] __read_mostly;
+static const struct nf_conntrack_expect_policy ftp_exp_policy = {
+ .max_expected = 1,
+ .timeout = 5 * 60,
+};
+
/* don't make this __exit, since it's called from __init ! */
static void nf_conntrack_ftp_fini(void)
{
@@ -556,8 +561,7 @@ static int __init nf_conntrack_ftp_init(void)
for (j = 0; j < 2; j++) {
ftp[i][j].tuple.src.u.tcp.port = htons(ports[i]);
ftp[i][j].tuple.dst.protonum = IPPROTO_TCP;
- ftp[i][j].max_expected = 1;
- ftp[i][j].timeout = 5 * 60; /* 5 Minutes */
+ ftp[i][j].expect_policy = &ftp_exp_policy;
ftp[i][j].me = THIS_MODULE;
ftp[i][j].help = help;
tmpname = &ftp_names[i][j][0];
diff --git a/net/netfilter/nf_conntrack_h323_main.c b/net/netfilter/nf_conntrack_h323_main.c
index 898f192..505052d 100644
--- a/net/netfilter/nf_conntrack_h323_main.c
+++ b/net/netfilter/nf_conntrack_h323_main.c
@@ -277,7 +277,8 @@ static int expect_rtp_rtcp(struct sk_buff *skb, struct nf_conn *ct,
/* Create expect for RTP */
if ((rtp_exp = nf_ct_expect_alloc(ct)) == NULL)
return -1;
- nf_ct_expect_init(rtp_exp, ct->tuplehash[!dir].tuple.src.l3num,
+ nf_ct_expect_init(rtp_exp, NF_CT_EXPECT_CLASS_DEFAULT,
+ ct->tuplehash[!dir].tuple.src.l3num,
&ct->tuplehash[!dir].tuple.src.u3,
&ct->tuplehash[!dir].tuple.dst.u3,
IPPROTO_UDP, NULL, &rtp_port);
@@ -287,7 +288,8 @@ static int expect_rtp_rtcp(struct sk_buff *skb, struct nf_conn *ct,
nf_ct_expect_put(rtp_exp);
return -1;
}
- nf_ct_expect_init(rtcp_exp, ct->tuplehash[!dir].tuple.src.l3num,
+ nf_ct_expect_init(rtcp_exp, NF_CT_EXPECT_CLASS_DEFAULT,
+ ct->tuplehash[!dir].tuple.src.l3num,
&ct->tuplehash[!dir].tuple.src.u3,
&ct->tuplehash[!dir].tuple.dst.u3,
IPPROTO_UDP, NULL, &rtcp_port);
@@ -344,7 +346,8 @@ static int expect_t120(struct sk_buff *skb,
/* Create expect for T.120 connections */
if ((exp = nf_ct_expect_alloc(ct)) == NULL)
return -1;
- nf_ct_expect_init(exp, ct->tuplehash[!dir].tuple.src.l3num,
+ nf_ct_expect_init(exp, NF_CT_EXPECT_CLASS_DEFAULT,
+ ct->tuplehash[!dir].tuple.src.l3num,
&ct->tuplehash[!dir].tuple.src.u3,
&ct->tuplehash[!dir].tuple.dst.u3,
IPPROTO_TCP, NULL, &port);
@@ -612,13 +615,17 @@ static int h245_help(struct sk_buff *skb, unsigned int protoff,
}
/****************************************************************************/
+static const struct nf_conntrack_expect_policy h245_exp_policy = {
+ .max_expected = H323_RTP_CHANNEL_MAX * 4 + 2 /* T.120 */,
+ .timeout = 240,
+};
+
static struct nf_conntrack_helper nf_conntrack_helper_h245 __read_mostly = {
.name = "H.245",
.me = THIS_MODULE,
- .max_expected = H323_RTP_CHANNEL_MAX * 4 + 2 /* T.120 */,
- .timeout = 240,
.tuple.dst.protonum = IPPROTO_UDP,
- .help = h245_help
+ .help = h245_help,
+ .expect_policy = &h245_exp_policy,
};
/****************************************************************************/
@@ -676,7 +683,8 @@ static int expect_h245(struct sk_buff *skb, struct nf_conn *ct,
/* Create expect for h245 connection */
if ((exp = nf_ct_expect_alloc(ct)) == NULL)
return -1;
- nf_ct_expect_init(exp, ct->tuplehash[!dir].tuple.src.l3num,
+ nf_ct_expect_init(exp, NF_CT_EXPECT_CLASS_DEFAULT,
+ ct->tuplehash[!dir].tuple.src.l3num,
&ct->tuplehash[!dir].tuple.src.u3,
&ct->tuplehash[!dir].tuple.dst.u3,
IPPROTO_TCP, NULL, &port);
@@ -792,7 +800,8 @@ static int expect_callforwarding(struct sk_buff *skb,
/* Create expect for the second call leg */
if ((exp = nf_ct_expect_alloc(ct)) == NULL)
return -1;
- nf_ct_expect_init(exp, ct->tuplehash[!dir].tuple.src.l3num,
+ nf_ct_expect_init(exp, NF_CT_EXPECT_CLASS_DEFAULT,
+ ct->tuplehash[!dir].tuple.src.l3num,
&ct->tuplehash[!dir].tuple.src.u3, &addr,
IPPROTO_TCP, NULL, &port);
exp->helper = nf_conntrack_helper_q931;
@@ -1156,28 +1165,30 @@ static int q931_help(struct sk_buff *skb, unsigned int protoff,
}
/****************************************************************************/
+static const struct nf_conntrack_expect_policy q931_exp_policy = {
+ /* T.120 and H.245 */
+ .max_expected = H323_RTP_CHANNEL_MAX * 4 + 4,
+ .timeout = 240,
+};
+
static struct nf_conntrack_helper nf_conntrack_helper_q931[] __read_mostly = {
{
.name = "Q.931",
.me = THIS_MODULE,
- /* T.120 and H.245 */
- .max_expected = H323_RTP_CHANNEL_MAX * 4 + 4,
- .timeout = 240,
.tuple.src.l3num = AF_INET,
.tuple.src.u.tcp.port = __constant_htons(Q931_PORT),
.tuple.dst.protonum = IPPROTO_TCP,
- .help = q931_help
+ .help = q931_help,
+ .expect_policy = &q931_exp_policy,
},
{
.name = "Q.931",
.me = THIS_MODULE,
- /* T.120 and H.245 */
- .max_expected = H323_RTP_CHANNEL_MAX * 4 + 4,
- .timeout = 240,
.tuple.src.l3num = AF_INET6,
.tuple.src.u.tcp.port = __constant_htons(Q931_PORT),
.tuple.dst.protonum = IPPROTO_TCP,
- .help = q931_help
+ .help = q931_help,
+ .expect_policy = &q931_exp_policy,
},
};
@@ -1261,7 +1272,8 @@ static int expect_q931(struct sk_buff *skb, struct nf_conn *ct,
/* Create expect for Q.931 */
if ((exp = nf_ct_expect_alloc(ct)) == NULL)
return -1;
- nf_ct_expect_init(exp, ct->tuplehash[!dir].tuple.src.l3num,
+ nf_ct_expect_init(exp, NF_CT_EXPECT_CLASS_DEFAULT,
+ ct->tuplehash[!dir].tuple.src.l3num,
gkrouted_only ? /* only accept calls from GK? */
&ct->tuplehash[!dir].tuple.src.u3 : NULL,
&ct->tuplehash[!dir].tuple.dst.u3,
@@ -1332,7 +1344,8 @@ static int process_gcf(struct sk_buff *skb, struct nf_conn *ct,
/* Need new expect */
if ((exp = nf_ct_expect_alloc(ct)) == NULL)
return -1;
- nf_ct_expect_init(exp, ct->tuplehash[!dir].tuple.src.l3num,
+ nf_ct_expect_init(exp, NF_CT_EXPECT_CLASS_DEFAULT,
+ ct->tuplehash[!dir].tuple.src.l3num,
&ct->tuplehash[!dir].tuple.src.u3, &addr,
IPPROTO_UDP, NULL, &port);
exp->helper = nf_conntrack_helper_ras;
@@ -1536,7 +1549,8 @@ static int process_acf(struct sk_buff *skb, struct nf_conn *ct,
/* Need new expect */
if ((exp = nf_ct_expect_alloc(ct)) == NULL)
return -1;
- nf_ct_expect_init(exp, ct->tuplehash[!dir].tuple.src.l3num,
+ nf_ct_expect_init(exp, NF_CT_EXPECT_CLASS_DEFAULT,
+ ct->tuplehash[!dir].tuple.src.l3num,
&ct->tuplehash[!dir].tuple.src.u3, &addr,
IPPROTO_TCP, NULL, &port);
exp->flags = NF_CT_EXPECT_PERMANENT;
@@ -1589,7 +1603,8 @@ static int process_lcf(struct sk_buff *skb, struct nf_conn *ct,
/* Need new expect for call signal */
if ((exp = nf_ct_expect_alloc(ct)) == NULL)
return -1;
- nf_ct_expect_init(exp, ct->tuplehash[!dir].tuple.src.l3num,
+ nf_ct_expect_init(exp, NF_CT_EXPECT_CLASS_DEFAULT,
+ ct->tuplehash[!dir].tuple.src.l3num,
&ct->tuplehash[!dir].tuple.src.u3, &addr,
IPPROTO_TCP, NULL, &port);
exp->flags = NF_CT_EXPECT_PERMANENT;
@@ -1728,26 +1743,29 @@ static int ras_help(struct sk_buff *skb, unsigned int protoff,
}
/****************************************************************************/
+static const struct nf_conntrack_expect_policy ras_exp_policy = {
+ .max_expected = 32,
+ .timeout = 240,
+};
+
static struct nf_conntrack_helper nf_conntrack_helper_ras[] __read_mostly = {
{
.name = "RAS",
.me = THIS_MODULE,
- .max_expected = 32,
- .timeout = 240,
.tuple.src.l3num = AF_INET,
.tuple.src.u.udp.port = __constant_htons(RAS_PORT),
.tuple.dst.protonum = IPPROTO_UDP,
.help = ras_help,
+ .expect_policy = &ras_exp_policy,
},
{
.name = "RAS",
.me = THIS_MODULE,
- .max_expected = 32,
- .timeout = 240,
.tuple.src.l3num = AF_INET6,
.tuple.src.u.udp.port = __constant_htons(RAS_PORT),
.tuple.dst.protonum = IPPROTO_UDP,
.help = ras_help,
+ .expect_policy = &ras_exp_policy,
},
};
diff --git a/net/netfilter/nf_conntrack_helper.c b/net/netfilter/nf_conntrack_helper.c
index b1fd21c..e350f56 100644
--- a/net/netfilter/nf_conntrack_helper.c
+++ b/net/netfilter/nf_conntrack_helper.c
@@ -110,7 +110,8 @@ int nf_conntrack_helper_register(struct nf_conntrack_helper *me)
{
unsigned int h = helper_hash(&me->tuple);
- BUG_ON(me->timeout == 0);
+ BUG_ON(me->expect_policy == NULL);
+ BUG_ON(me->expect_class_max >= NF_CT_MAX_EXPECT_CLASSES);
mutex_lock(&nf_ct_helper_mutex);
hlist_add_head_rcu(&me->hnode, &nf_ct_helper_hash[h]);
diff --git a/net/netfilter/nf_conntrack_irc.c b/net/netfilter/nf_conntrack_irc.c
index c336b07..02f21cb 100644
--- a/net/netfilter/nf_conntrack_irc.c
+++ b/net/netfilter/nf_conntrack_irc.c
@@ -187,7 +187,8 @@ static int help(struct sk_buff *skb, unsigned int protoff,
}
tuple = &ct->tuplehash[!dir].tuple;
port = htons(dcc_port);
- nf_ct_expect_init(exp, tuple->src.l3num,
+ nf_ct_expect_init(exp, NF_CT_EXPECT_CLASS_DEFAULT,
+ tuple->src.l3num,
NULL, &tuple->dst.u3,
IPPROTO_TCP, NULL, &port);
@@ -210,6 +211,7 @@ static int help(struct sk_buff *skb, unsigned int protoff,
static struct nf_conntrack_helper irc[MAX_PORTS] __read_mostly;
static char irc_names[MAX_PORTS][sizeof("irc-65535")] __read_mostly;
+static struct nf_conntrack_expect_policy irc_exp_policy;
static void nf_conntrack_irc_fini(void);
@@ -223,6 +225,9 @@ static int __init nf_conntrack_irc_init(void)
return -EINVAL;
}
+ irc_exp_policy.max_expected = max_dcc_channels;
+ irc_exp_policy.timeout = dcc_timeout;
+
irc_buffer = kmalloc(65536, GFP_KERNEL);
if (!irc_buffer)
return -ENOMEM;
@@ -235,8 +240,7 @@ static int __init nf_conntrack_irc_init(void)
irc[i].tuple.src.l3num = AF_INET;
irc[i].tuple.src.u.tcp.port = htons(ports[i]);
irc[i].tuple.dst.protonum = IPPROTO_TCP;
- irc[i].max_expected = max_dcc_channels;
- irc[i].timeout = dcc_timeout;
+ irc[i].expect_policy = &irc_exp_policy;
irc[i].me = THIS_MODULE;
irc[i].help = help;
diff --git a/net/netfilter/nf_conntrack_netbios_ns.c b/net/netfilter/nf_conntrack_netbios_ns.c
index 60dedad..08404e6 100644
--- a/net/netfilter/nf_conntrack_netbios_ns.c
+++ b/net/netfilter/nf_conntrack_netbios_ns.c
@@ -86,6 +86,7 @@ static int help(struct sk_buff *skb, unsigned int protoff,
exp->expectfn = NULL;
exp->flags = NF_CT_EXPECT_PERMANENT;
+ exp->class = NF_CT_EXPECT_CLASS_DEFAULT;
exp->helper = NULL;
nf_ct_expect_related(exp);
@@ -96,19 +97,23 @@ out:
return NF_ACCEPT;
}
+static struct nf_conntrack_expect_policy exp_policy = {
+ .max_expected = 1,
+};
+
static struct nf_conntrack_helper helper __read_mostly = {
.name = "netbios-ns",
.tuple.src.l3num = AF_INET,
.tuple.src.u.udp.port = __constant_htons(NMBD_PORT),
.tuple.dst.protonum = IPPROTO_UDP,
- .max_expected = 1,
.me = THIS_MODULE,
.help = help,
+ .expect_policy = &exp_policy,
};
static int __init nf_conntrack_netbios_ns_init(void)
{
- helper.timeout = timeout;
+ exp_policy.timeout = timeout;
return nf_conntrack_helper_register(&helper);
}
diff --git a/net/netfilter/nf_conntrack_pptp.c b/net/netfilter/nf_conntrack_pptp.c
index b5cb8e8..8fd8347 100644
--- a/net/netfilter/nf_conntrack_pptp.c
+++ b/net/netfilter/nf_conntrack_pptp.c
@@ -208,7 +208,8 @@ static int exp_gre(struct nf_conn *ct, __be16 callid, __be16 peer_callid)
/* original direction, PNS->PAC */
dir = IP_CT_DIR_ORIGINAL;
- nf_ct_expect_init(exp_orig, ct->tuplehash[dir].tuple.src.l3num,
+ nf_ct_expect_init(exp_orig, NF_CT_EXPECT_CLASS_DEFAULT,
+ ct->tuplehash[dir].tuple.src.l3num,
&ct->tuplehash[dir].tuple.src.u3,
&ct->tuplehash[dir].tuple.dst.u3,
IPPROTO_GRE, &peer_callid, &callid);
@@ -216,7 +217,8 @@ static int exp_gre(struct nf_conn *ct, __be16 callid, __be16 peer_callid)
/* reply direction, PAC->PNS */
dir = IP_CT_DIR_REPLY;
- nf_ct_expect_init(exp_reply, ct->tuplehash[dir].tuple.src.l3num,
+ nf_ct_expect_init(exp_reply, NF_CT_EXPECT_CLASS_DEFAULT,
+ ct->tuplehash[dir].tuple.src.l3num,
&ct->tuplehash[dir].tuple.src.u3,
&ct->tuplehash[dir].tuple.dst.u3,
IPPROTO_GRE, &callid, &peer_callid);
@@ -575,17 +577,21 @@ conntrack_pptp_help(struct sk_buff *skb, unsigned int protoff,
return ret;
}
+static const struct nf_conntrack_expect_policy pptp_exp_policy = {
+ .max_expected = 2,
+ .timeout = 5 * 60,
+};
+
/* control protocol helper */
static struct nf_conntrack_helper pptp __read_mostly = {
.name = "pptp",
.me = THIS_MODULE,
- .max_expected = 2,
- .timeout = 5 * 60,
.tuple.src.l3num = AF_INET,
.tuple.src.u.tcp.port = __constant_htons(PPTP_CONTROL_PORT),
.tuple.dst.protonum = IPPROTO_TCP,
.help = conntrack_pptp_help,
.destroy = pptp_destroy_siblings,
+ .expect_policy = &pptp_exp_policy,
};
static int __init nf_conntrack_pptp_init(void)
diff --git a/net/netfilter/nf_conntrack_sane.c b/net/netfilter/nf_conntrack_sane.c
index a70051d..7542e25 100644
--- a/net/netfilter/nf_conntrack_sane.c
+++ b/net/netfilter/nf_conntrack_sane.c
@@ -143,7 +143,8 @@ static int help(struct sk_buff *skb,
}
tuple = &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple;
- nf_ct_expect_init(exp, family, &tuple->src.u3, &tuple->dst.u3,
+ nf_ct_expect_init(exp, NF_CT_EXPECT_CLASS_DEFAULT, family,
+ &tuple->src.u3, &tuple->dst.u3,
IPPROTO_TCP, NULL, &reply->port);
pr_debug("nf_ct_sane: expect: ");
@@ -163,6 +164,11 @@ out:
static struct nf_conntrack_helper sane[MAX_PORTS][2] __read_mostly;
static char sane_names[MAX_PORTS][2][sizeof("sane-65535")] __read_mostly;
+static const struct nf_conntrack_expect_policy sane_exp_policy = {
+ .max_expected = 1,
+ .timeout = 5 * 60,
+};
+
/* don't make this __exit, since it's called from __init ! */
static void nf_conntrack_sane_fini(void)
{
@@ -200,8 +206,7 @@ static int __init nf_conntrack_sane_init(void)
for (j = 0; j < 2; j++) {
sane[i][j].tuple.src.u.tcp.port = htons(ports[i]);
sane[i][j].tuple.dst.protonum = IPPROTO_TCP;
- sane[i][j].max_expected = 1;
- sane[i][j].timeout = 5 * 60; /* 5 Minutes */
+ sane[i][j].expect_policy = &sane_exp_policy;
sane[i][j].me = THIS_MODULE;
sane[i][j].help = help;
tmpname = &sane_names[i][j][0];
diff --git a/net/netfilter/nf_conntrack_sip.c b/net/netfilter/nf_conntrack_sip.c
index c521c89..0021d5b 100644
--- a/net/netfilter/nf_conntrack_sip.c
+++ b/net/netfilter/nf_conntrack_sip.c
@@ -380,7 +380,7 @@ static int set_expected_rtp(struct sk_buff *skb,
exp = nf_ct_expect_alloc(ct);
if (exp == NULL)
return NF_DROP;
- nf_ct_expect_init(exp, family,
+ nf_ct_expect_init(exp, NF_CT_EXPECT_CLASS_DEFAULT, family,
&ct->tuplehash[!dir].tuple.src.u3, addr,
IPPROTO_UDP, NULL, &port);
@@ -476,6 +476,11 @@ out:
static struct nf_conntrack_helper sip[MAX_PORTS][2] __read_mostly;
static char sip_names[MAX_PORTS][2][sizeof("sip-65535")] __read_mostly;
+static const struct nf_conntrack_expect_policy sip_exp_policy = {
+ .max_expected = 2,
+ .timeout = 3 * 60,
+};
+
static void nf_conntrack_sip_fini(void)
{
int i, j;
@@ -505,8 +510,7 @@ static int __init nf_conntrack_sip_init(void)
for (j = 0; j < 2; j++) {
sip[i][j].tuple.dst.protonum = IPPROTO_UDP;
sip[i][j].tuple.src.u.udp.port = htons(ports[i]);
- sip[i][j].max_expected = 2;
- sip[i][j].timeout = 3 * 60; /* 3 minutes */
+ sip[i][j].expect_policy = &sip_exp_policy;
sip[i][j].me = THIS_MODULE;
sip[i][j].help = sip_help;
diff --git a/net/netfilter/nf_conntrack_tftp.c b/net/netfilter/nf_conntrack_tftp.c
index bd2e800..a28341b 100644
--- a/net/netfilter/nf_conntrack_tftp.c
+++ b/net/netfilter/nf_conntrack_tftp.c
@@ -63,7 +63,8 @@ static int tftp_help(struct sk_buff *skb,
if (exp == NULL)
return NF_DROP;
tuple = &ct->tuplehash[IP_CT_DIR_REPLY].tuple;
- nf_ct_expect_init(exp, family, &tuple->src.u3, &tuple->dst.u3,
+ nf_ct_expect_init(exp, NF_CT_EXPECT_CLASS_DEFAULT, family,
+ &tuple->src.u3, &tuple->dst.u3,
IPPROTO_UDP, NULL, &tuple->dst.u.udp.port);
pr_debug("expect: ");
@@ -92,6 +93,11 @@ static int tftp_help(struct sk_buff *skb,
static struct nf_conntrack_helper tftp[MAX_PORTS][2] __read_mostly;
static char tftp_names[MAX_PORTS][2][sizeof("tftp-65535")] __read_mostly;
+static const struct nf_conntrack_expect_policy tftp_exp_policy = {
+ .max_expected = 1,
+ .timeout = 5 * 60,
+};
+
static void nf_conntrack_tftp_fini(void)
{
int i, j;
@@ -118,8 +124,7 @@ static int __init nf_conntrack_tftp_init(void)
for (j = 0; j < 2; j++) {
tftp[i][j].tuple.dst.protonum = IPPROTO_UDP;
tftp[i][j].tuple.src.u.udp.port = htons(ports[i]);
- tftp[i][j].max_expected = 1;
- tftp[i][j].timeout = 5 * 60; /* 5 minutes */
+ tftp[i][j].expect_policy = &tftp_exp_policy;
tftp[i][j].me = THIS_MODULE;
tftp[i][j].help = tftp_help;
^ permalink raw reply related [flat|nested] 39+ messages in thread* Re: [NETFILTER 06/32]: nf_conntrack: introduce expectation classes and policies
2008-03-25 14:14 ` [NETFILTER 06/32]: nf_conntrack: introduce expectation classes and policies Patrick McHardy
@ 2008-03-25 15:46 ` Jan Engelhardt
2008-03-25 15:51 ` Patrick McHardy
0 siblings, 1 reply; 39+ messages in thread
From: Jan Engelhardt @ 2008-03-25 15:46 UTC (permalink / raw)
To: Patrick McHardy; +Cc: davem, netfilter-devel
On Tuesday 2008-03-25 15:14, Patrick McHardy wrote:
> /****************************************************************************/
> +static const struct nf_conntrack_expect_policy h245_exp_policy = {
> + .max_expected = H323_RTP_CHANNEL_MAX * 4 + 2 /* T.120 */,
> + .timeout = 240,
> +};
> +
Developer questions: what does ->max_expected limit?
Expectations for one connection, or for the whole helper module?
>@@ -110,7 +110,8 @@ int nf_conntrack_helper_register(struct nf_conntrack_helper *me)
> {
> unsigned int h = helper_hash(&me->tuple);
>
>- BUG_ON(me->timeout == 0);
>+ BUG_ON(me->expect_policy == NULL);
>+ BUG_ON(me->expect_class_max >= NF_CT_MAX_EXPECT_CLASSES);
>
> mutex_lock(&nf_ct_helper_mutex);
> hlist_add_head_rcu(&me->hnode, &nf_ct_helper_hash[h]);
A zero timeout triggered a BUG_ON in nf_conntrack_helper_register,
now this check is gone!?
^ permalink raw reply [flat|nested] 39+ messages in thread* Re: [NETFILTER 06/32]: nf_conntrack: introduce expectation classes and policies
2008-03-25 15:46 ` Jan Engelhardt
@ 2008-03-25 15:51 ` Patrick McHardy
0 siblings, 0 replies; 39+ messages in thread
From: Patrick McHardy @ 2008-03-25 15:51 UTC (permalink / raw)
To: Jan Engelhardt; +Cc: davem, netfilter-devel
Jan Engelhardt wrote:
>
>
> On Tuesday 2008-03-25 15:14, Patrick McHardy wrote:
>
>> /****************************************************************************/
>>
>> +static const struct nf_conntrack_expect_policy h245_exp_policy = {
>> + .max_expected = H323_RTP_CHANNEL_MAX * 4 + 2 /* T.120 */,
>> + .timeout = 240,
>> +};
>> +
>
> Developer questions: what does ->max_expected limit?
> Expectations for one connection, or for the whole helper module?
Unfulfilled expectations per conntrack.
>> @@ -110,7 +110,8 @@ int nf_conntrack_helper_register(struct
>> nf_conntrack_helper *me)
>> {
>> unsigned int h = helper_hash(&me->tuple);
>>
>> - BUG_ON(me->timeout == 0);
>> + BUG_ON(me->expect_policy == NULL);
>> + BUG_ON(me->expect_class_max >= NF_CT_MAX_EXPECT_CLASSES);
>>
>> mutex_lock(&nf_ct_helper_mutex);
>> hlist_add_head_rcu(&me->hnode, &nf_ct_helper_hash[h]);
>
> A zero timeout triggered a BUG_ON in nf_conntrack_helper_register,
> now this check is gone!?
Yes, it requires iterating through the policies,
which is too much trouble for checking a developer
bug (and no module in the kernel does this). In fact
the SNMP NAT helper sets a fake timeout to avoid
triggering the BUG_ON since it never registers any
expectations.
^ permalink raw reply [flat|nested] 39+ messages in thread
* [NETFILTER 07/32]: Add nf_inet_addr_cmp()
2008-03-25 14:14 [METFILTER 00/32]: SIP helper update Patrick McHardy
` (5 preceding siblings ...)
2008-03-25 14:14 ` [NETFILTER 06/32]: nf_conntrack: introduce expectation classes and policies Patrick McHardy
@ 2008-03-25 14:15 ` Patrick McHardy
2008-03-25 14:15 ` [NETFILTER 08/32]: nf_nat_sip: fix NAT setup order Patrick McHardy
` (25 subsequent siblings)
32 siblings, 0 replies; 39+ messages in thread
From: Patrick McHardy @ 2008-03-25 14:15 UTC (permalink / raw)
To: davem; +Cc: Patrick McHardy, netfilter-devel
[NETFILTER]: Add nf_inet_addr_cmp()
Signed-off-by: Patrick McHardy <kaber@trash.net>
---
commit 14d510e3026c99ebd8531e8ea0acb574545b5c42
tree aca9464205040aa5daa25a50a0e98443f905eb0b
parent 48bb8ab5591cab986a2850facf33998357db3b10
author Patrick McHardy <kaber@trash.net> Tue, 25 Mar 2008 13:44:45 +0100
committer Patrick McHardy <kaber@trash.net> Tue, 25 Mar 2008 13:44:45 +0100
include/linux/netfilter.h | 9 +++++++++
include/net/netfilter/nf_conntrack_tuple.h | 15 +++------------
2 files changed, 12 insertions(+), 12 deletions(-)
diff --git a/include/linux/netfilter.h b/include/linux/netfilter.h
index f0680c2..89e6c72 100644
--- a/include/linux/netfilter.h
+++ b/include/linux/netfilter.h
@@ -61,6 +61,15 @@ union nf_inet_addr {
#ifdef __KERNEL__
#ifdef CONFIG_NETFILTER
+static inline int nf_inet_addr_cmp(const union nf_inet_addr *a1,
+ const union nf_inet_addr *a2)
+{
+ return a1->all[0] == a2->all[0] &&
+ a1->all[1] == a2->all[1] &&
+ a1->all[2] == a2->all[2] &&
+ a1->all[3] == a2->all[3];
+}
+
extern void netfilter_init(void);
/* Largest hook number + 1 */
diff --git a/include/net/netfilter/nf_conntrack_tuple.h b/include/net/netfilter/nf_conntrack_tuple.h
index d9b53dd..168c917 100644
--- a/include/net/netfilter/nf_conntrack_tuple.h
+++ b/include/net/netfilter/nf_conntrack_tuple.h
@@ -163,10 +163,7 @@ struct nf_conntrack_tuple_hash
static inline int __nf_ct_tuple_src_equal(const struct nf_conntrack_tuple *t1,
const struct nf_conntrack_tuple *t2)
{
- return (t1->src.u3.all[0] == t2->src.u3.all[0] &&
- t1->src.u3.all[1] == t2->src.u3.all[1] &&
- t1->src.u3.all[2] == t2->src.u3.all[2] &&
- t1->src.u3.all[3] == t2->src.u3.all[3] &&
+ return (nf_inet_addr_cmp(&t1->src.u3, &t2->src.u3) &&
t1->src.u.all == t2->src.u.all &&
t1->src.l3num == t2->src.l3num);
}
@@ -174,10 +171,7 @@ static inline int __nf_ct_tuple_src_equal(const struct nf_conntrack_tuple *t1,
static inline int __nf_ct_tuple_dst_equal(const struct nf_conntrack_tuple *t1,
const struct nf_conntrack_tuple *t2)
{
- return (t1->dst.u3.all[0] == t2->dst.u3.all[0] &&
- t1->dst.u3.all[1] == t2->dst.u3.all[1] &&
- t1->dst.u3.all[2] == t2->dst.u3.all[2] &&
- t1->dst.u3.all[3] == t2->dst.u3.all[3] &&
+ return (nf_inet_addr_cmp(&t1->dst.u3, &t2->dst.u3) &&
t1->dst.u.all == t2->dst.u.all &&
t1->dst.protonum == t2->dst.protonum);
}
@@ -192,10 +186,7 @@ static inline int nf_ct_tuple_equal(const struct nf_conntrack_tuple *t1,
static inline int nf_ct_tuple_mask_equal(const struct nf_conntrack_tuple_mask *m1,
const struct nf_conntrack_tuple_mask *m2)
{
- return (m1->src.u3.all[0] == m2->src.u3.all[0] &&
- m1->src.u3.all[1] == m2->src.u3.all[1] &&
- m1->src.u3.all[2] == m2->src.u3.all[2] &&
- m1->src.u3.all[3] == m2->src.u3.all[3] &&
+ return (nf_inet_addr_cmp(&m1->src.u3, &m2->src.u3) &&
m1->src.u.all == m2->src.u.all);
}
^ permalink raw reply related [flat|nested] 39+ messages in thread* [NETFILTER 08/32]: nf_nat_sip: fix NAT setup order
2008-03-25 14:14 [METFILTER 00/32]: SIP helper update Patrick McHardy
` (6 preceding siblings ...)
2008-03-25 14:15 ` [NETFILTER 07/32]: Add nf_inet_addr_cmp() Patrick McHardy
@ 2008-03-25 14:15 ` Patrick McHardy
2008-03-25 14:15 ` [NETFILTER 09/32]: nf_conntrack_sip: fix some off-by-ones Patrick McHardy
` (24 subsequent siblings)
32 siblings, 0 replies; 39+ messages in thread
From: Patrick McHardy @ 2008-03-25 14:15 UTC (permalink / raw)
To: davem; +Cc: Patrick McHardy, netfilter-devel
[NETFILTER]: nf_nat_sip: fix NAT setup order
We need to set up the destination NAT mapping before the source NAT
mapping, so the NAT core gets to see the final tuple and can decide
whether the source port needs to be remapped.
Signed-off-by: Patrick McHardy <kaber@trash.net>
---
commit b76b0afe5818cb9aac50d57e0be319935f58ed64
tree aecf418e8d77a75e0fdbf8250a2e9fe028131c13
parent 14d510e3026c99ebd8531e8ea0acb574545b5c42
author Patrick McHardy <kaber@trash.net> Tue, 25 Mar 2008 12:44:48 +0100
committer Patrick McHardy <kaber@trash.net> Tue, 25 Mar 2008 14:09:53 +0100
net/ipv4/netfilter/nf_nat_sip.c | 12 ++++++------
1 files changed, 6 insertions(+), 6 deletions(-)
diff --git a/net/ipv4/netfilter/nf_nat_sip.c b/net/ipv4/netfilter/nf_nat_sip.c
index b4c8d49..84d8b49 100644
--- a/net/ipv4/netfilter/nf_nat_sip.c
+++ b/net/ipv4/netfilter/nf_nat_sip.c
@@ -224,17 +224,17 @@ static void ip_nat_sdp_expect(struct nf_conn *ct,
/* This must be a fresh one. */
BUG_ON(ct->status & IPS_NAT_DONE_MASK);
- /* Change src to where master sends to */
- range.flags = IP_NAT_RANGE_MAP_IPS;
- range.min_ip = range.max_ip
- = ct->master->tuplehash[!exp->dir].tuple.dst.u3.ip;
- nf_nat_setup_info(ct, &range, IP_NAT_MANIP_SRC);
-
/* For DST manip, map port here to where it's expected. */
range.flags = (IP_NAT_RANGE_MAP_IPS | IP_NAT_RANGE_PROTO_SPECIFIED);
range.min = range.max = exp->saved_proto;
range.min_ip = range.max_ip = exp->saved_ip;
nf_nat_setup_info(ct, &range, IP_NAT_MANIP_DST);
+
+ /* Change src to where master sends to */
+ range.flags = IP_NAT_RANGE_MAP_IPS;
+ range.min_ip = range.max_ip
+ = ct->master->tuplehash[!exp->dir].tuple.dst.u3.ip;
+ nf_nat_setup_info(ct, &range, IP_NAT_MANIP_SRC);
}
/* So, this packet has hit the connection tracking matching code.
^ permalink raw reply related [flat|nested] 39+ messages in thread* [NETFILTER 09/32]: nf_conntrack_sip: fix some off-by-ones
2008-03-25 14:14 [METFILTER 00/32]: SIP helper update Patrick McHardy
` (7 preceding siblings ...)
2008-03-25 14:15 ` [NETFILTER 08/32]: nf_nat_sip: fix NAT setup order Patrick McHardy
@ 2008-03-25 14:15 ` Patrick McHardy
2008-03-25 14:15 ` [NETFILTER 10/32]: nf_conntrack_sip: adjust dptr and datalen after packet mangling Patrick McHardy
` (23 subsequent siblings)
32 siblings, 0 replies; 39+ messages in thread
From: Patrick McHardy @ 2008-03-25 14:15 UTC (permalink / raw)
To: davem; +Cc: Patrick McHardy, netfilter-devel
[NETFILTER]: nf_conntrack_sip: fix some off-by-ones
"limit" marks the first character outside the bounds.
Signed-off-by: Patrick McHardy <kaber@trash.net>
---
commit 3e654acbb82002c6fdc57573c8167ade5608dbd3
tree e04d2649131a18732f66d253366d9d3962a5d1bc
parent b76b0afe5818cb9aac50d57e0be319935f58ed64
author Patrick McHardy <kaber@trash.net> Tue, 25 Mar 2008 12:44:50 +0100
committer Patrick McHardy <kaber@trash.net> Tue, 25 Mar 2008 14:09:54 +0100
net/netfilter/nf_conntrack_sip.c | 16 ++++++++--------
1 files changed, 8 insertions(+), 8 deletions(-)
diff --git a/net/netfilter/nf_conntrack_sip.c b/net/netfilter/nf_conntrack_sip.c
index 0021d5b..016e1c1 100644
--- a/net/netfilter/nf_conntrack_sip.c
+++ b/net/netfilter/nf_conntrack_sip.c
@@ -192,10 +192,10 @@ int ct_sip_lnlen(const char *line, const char *limit)
{
const char *k = line;
- while ((line <= limit) && (*line == '\r' || *line == '\n'))
+ while ((line < limit) && (*line == '\r' || *line == '\n'))
line++;
- while (line <= limit) {
+ while (line < limit) {
if (*line == '\r' || *line == '\n')
break;
line++;
@@ -211,7 +211,7 @@ const char *ct_sip_search(const char *needle, const char *haystack,
{
const char *limit = haystack + (haystack_len - needle_len);
- while (haystack <= limit) {
+ while (haystack < limit) {
if (case_sensitive) {
if (strncmp(haystack, needle, needle_len) == 0)
return haystack;
@@ -229,7 +229,7 @@ static int digits_len(const struct nf_conn *ct, const char *dptr,
const char *limit, int *shift)
{
int len = 0;
- while (dptr <= limit && isdigit(*dptr)) {
+ while (dptr < limit && isdigit(*dptr)) {
dptr++;
len++;
}
@@ -240,7 +240,7 @@ static int digits_len(const struct nf_conn *ct, const char *dptr,
static int skp_digits_len(const struct nf_conn *ct, const char *dptr,
const char *limit, int *shift)
{
- for (; dptr <= limit && *dptr == ' '; dptr++)
+ for (; dptr < limit && *dptr == ' '; dptr++)
(*shift)++;
return digits_len(ct, dptr, limit, shift);
@@ -302,13 +302,13 @@ static int skp_epaddr_len(const struct nf_conn *ct, const char *dptr,
/* Search for @, but stop at the end of the line.
* We are inside a sip: URI, so we don't need to worry about
* continuation lines. */
- while (dptr <= limit &&
+ while (dptr < limit &&
*dptr != '@' && *dptr != '\r' && *dptr != '\n') {
(*shift)++;
dptr++;
}
- if (dptr <= limit && *dptr == '@') {
+ if (dptr < limit && *dptr == '@') {
dptr++;
(*shift)++;
} else {
@@ -332,7 +332,7 @@ int ct_sip_get_info(const struct nf_conn *ct,
limit = dptr + (dlen - hnfo->lnlen);
- while (dptr <= limit) {
+ while (dptr < limit) {
if ((strncmp(dptr, hnfo->lname, hnfo->lnlen) != 0) &&
(hnfo->sname == NULL ||
strncmp(dptr, hnfo->sname, hnfo->snlen) != 0)) {
^ permalink raw reply related [flat|nested] 39+ messages in thread* [NETFILTER 10/32]: nf_conntrack_sip: adjust dptr and datalen after packet mangling
2008-03-25 14:14 [METFILTER 00/32]: SIP helper update Patrick McHardy
` (8 preceding siblings ...)
2008-03-25 14:15 ` [NETFILTER 09/32]: nf_conntrack_sip: fix some off-by-ones Patrick McHardy
@ 2008-03-25 14:15 ` Patrick McHardy
2008-03-25 14:15 ` [NETFILTER 11/32]: nf_conntrack_sip: remove redundant function arguments Patrick McHardy
` (22 subsequent siblings)
32 siblings, 0 replies; 39+ messages in thread
From: Patrick McHardy @ 2008-03-25 14:15 UTC (permalink / raw)
To: davem; +Cc: Patrick McHardy, netfilter-devel
[NETFILTER]: nf_conntrack_sip: adjust dptr and datalen after packet mangling
After mangling the packet, the pointer to the data and the length of the data
portion may change and need to be adjusted.
Use double data pointers and a pointer to the length everywhere and add a
helper function to the NAT helper for performing the adjustments.
Signed-off-by: Patrick McHardy <kaber@trash.net>
---
commit cc0d0b162f0e36ddfd0b9fbed58a39a2d1561fb6
tree 653d23b2e4bb220d75bba2ffd358aec10a99d937
parent 3e654acbb82002c6fdc57573c8167ade5608dbd3
author Patrick McHardy <kaber@trash.net> Tue, 25 Mar 2008 12:44:52 +0100
committer Patrick McHardy <kaber@trash.net> Tue, 25 Mar 2008 14:09:54 +0100
include/linux/netfilter/nf_conntrack_sip.h | 6 +-
net/ipv4/netfilter/nf_nat_sip.c | 91 +++++++++++++++-------------
net/netfilter/nf_conntrack_sip.c | 14 ++--
3 files changed, 60 insertions(+), 51 deletions(-)
diff --git a/include/linux/netfilter/nf_conntrack_sip.h b/include/linux/netfilter/nf_conntrack_sip.h
index 8e5ce1c..9d0dbfb 100644
--- a/include/linux/netfilter/nf_conntrack_sip.h
+++ b/include/linux/netfilter/nf_conntrack_sip.h
@@ -24,11 +24,13 @@ enum sip_header_pos {
extern unsigned int (*nf_nat_sip_hook)(struct sk_buff *skb,
enum ip_conntrack_info ctinfo,
struct nf_conn *ct,
- const char **dptr);
+ const char **dptr,
+ unsigned int *datalen);
extern unsigned int (*nf_nat_sdp_hook)(struct sk_buff *skb,
enum ip_conntrack_info ctinfo,
struct nf_conntrack_expect *exp,
- const char *dptr);
+ const char **dptr,
+ unsigned int *datalen);
extern int ct_sip_get_info(const struct nf_conn *ct, const char *dptr,
size_t dlen, unsigned int *matchoff,
diff --git a/net/ipv4/netfilter/nf_nat_sip.c b/net/ipv4/netfilter/nf_nat_sip.c
index 84d8b49..e77122e 100644
--- a/net/ipv4/netfilter/nf_nat_sip.c
+++ b/net/ipv4/netfilter/nf_nat_sip.c
@@ -60,15 +60,35 @@ static void addr_map_init(const struct nf_conn *ct, struct addr_map *map)
}
}
+static unsigned int mangle_packet(struct sk_buff *skb,
+ const char **dptr, unsigned int *datalen,
+ unsigned int matchoff, unsigned int matchlen,
+ const char *buffer, unsigned int buflen)
+{
+ enum ip_conntrack_info ctinfo;
+ struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
+
+ if (!nf_nat_mangle_udp_packet(skb, ct, ctinfo, matchoff, matchlen,
+ buffer, buflen))
+ return 0;
+
+ /* Reload data pointer and adjust datalen value */
+ *dptr = skb->data + ip_hdrlen(skb) + sizeof(struct udphdr);
+ *datalen += buflen - matchlen;
+ return 1;
+}
+
static int map_sip_addr(struct sk_buff *skb, enum ip_conntrack_info ctinfo,
- struct nf_conn *ct, const char **dptr, size_t dlen,
+ struct nf_conn *ct,
+ const char **dptr, unsigned int *datalen,
enum sip_header_pos pos, struct addr_map *map)
{
enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
unsigned int matchlen, matchoff, addrlen;
char *addr;
- if (ct_sip_get_info(ct, *dptr, dlen, &matchoff, &matchlen, pos) <= 0)
+ if (ct_sip_get_info(ct, *dptr, *datalen, &matchoff, &matchlen,
+ pos) <= 0)
return 1;
if ((matchlen == map->addr[dir].srciplen ||
@@ -84,26 +104,19 @@ static int map_sip_addr(struct sk_buff *skb, enum ip_conntrack_info ctinfo,
} else
return 1;
- if (!nf_nat_mangle_udp_packet(skb, ct, ctinfo,
- matchoff, matchlen, addr, addrlen))
- return 0;
- *dptr = skb->data + ip_hdrlen(skb) + sizeof(struct udphdr);
- return 1;
-
+ return mangle_packet(skb, dptr, datalen, matchoff, matchlen,
+ addr, addrlen);
}
static unsigned int ip_nat_sip(struct sk_buff *skb,
enum ip_conntrack_info ctinfo,
struct nf_conn *ct,
- const char **dptr)
+ const char **dptr, unsigned int *datalen)
{
enum sip_header_pos pos;
struct addr_map map;
- int dataoff, datalen;
- dataoff = ip_hdrlen(skb) + sizeof(struct udphdr);
- datalen = skb->len - dataoff;
- if (datalen < sizeof("SIP/2.0") - 1)
+ if (*datalen < sizeof("SIP/2.0") - 1)
return NF_ACCEPT;
addr_map_init(ct, &map);
@@ -115,7 +128,7 @@ static unsigned int ip_nat_sip(struct sk_buff *skb,
* The "userinfo" and "@" components of the SIP URI MUST NOT
* be present.
*/
- if (datalen >= sizeof("REGISTER") - 1 &&
+ if (*datalen >= sizeof("REGISTER") - 1 &&
strncmp(*dptr, "REGISTER", sizeof("REGISTER") - 1) == 0)
pos = POS_REG_REQ_URI;
else
@@ -136,51 +149,45 @@ static unsigned int ip_nat_sip(struct sk_buff *skb,
static unsigned int mangle_sip_packet(struct sk_buff *skb,
enum ip_conntrack_info ctinfo,
struct nf_conn *ct,
- const char **dptr, size_t dlen,
+ const char **dptr, unsigned int *datalen,
char *buffer, int bufflen,
enum sip_header_pos pos)
{
unsigned int matchlen, matchoff;
- if (ct_sip_get_info(ct, *dptr, dlen, &matchoff, &matchlen, pos) <= 0)
- return 0;
-
- if (!nf_nat_mangle_udp_packet(skb, ct, ctinfo,
- matchoff, matchlen, buffer, bufflen))
+ if (ct_sip_get_info(ct, *dptr, *datalen, &matchoff, &matchlen,
+ pos) <= 0)
return 0;
- /* We need to reload this. Thanks Patrick. */
- *dptr = skb->data + ip_hdrlen(skb) + sizeof(struct udphdr);
- return 1;
+ return mangle_packet(skb, dptr, datalen, matchoff, matchlen,
+ buffer, bufflen);
}
static int mangle_content_len(struct sk_buff *skb,
enum ip_conntrack_info ctinfo,
struct nf_conn *ct,
- const char *dptr)
+ const char **dptr, unsigned int *datalen)
{
- unsigned int dataoff, matchoff, matchlen;
+ unsigned int matchoff, matchlen;
char buffer[sizeof("65536")];
int bufflen;
- dataoff = ip_hdrlen(skb) + sizeof(struct udphdr);
-
/* Get actual SDP length */
- if (ct_sip_get_info(ct, dptr, skb->len - dataoff, &matchoff,
+ if (ct_sip_get_info(ct, *dptr, *datalen, &matchoff,
&matchlen, POS_SDP_HEADER) > 0) {
/* since ct_sip_get_info() give us a pointer passing 'v='
we need to add 2 bytes in this count. */
- int c_len = skb->len - dataoff - matchoff + 2;
+ int c_len = *datalen - matchoff + 2;
/* Now, update SDP length */
- if (ct_sip_get_info(ct, dptr, skb->len - dataoff, &matchoff,
+ if (ct_sip_get_info(ct, *dptr, *datalen, &matchoff,
&matchlen, POS_CONTENT) > 0) {
bufflen = sprintf(buffer, "%u", c_len);
- return nf_nat_mangle_udp_packet(skb, ct, ctinfo,
- matchoff, matchlen,
- buffer, bufflen);
+ return mangle_packet(skb, dptr, datalen,
+ matchoff, matchlen,
+ buffer, bufflen);
}
}
return 0;
@@ -190,30 +197,28 @@ static unsigned int mangle_sdp(struct sk_buff *skb,
enum ip_conntrack_info ctinfo,
struct nf_conn *ct,
__be32 newip, u_int16_t port,
- const char *dptr)
+ const char **dptr, unsigned int *datalen)
{
char buffer[sizeof("nnn.nnn.nnn.nnn")];
- unsigned int dataoff, bufflen;
-
- dataoff = ip_hdrlen(skb) + sizeof(struct udphdr);
+ unsigned int bufflen;
/* Mangle owner and contact info. */
bufflen = sprintf(buffer, "%u.%u.%u.%u", NIPQUAD(newip));
- if (!mangle_sip_packet(skb, ctinfo, ct, &dptr, skb->len - dataoff,
+ if (!mangle_sip_packet(skb, ctinfo, ct, dptr, datalen,
buffer, bufflen, POS_OWNER_IP4))
return 0;
- if (!mangle_sip_packet(skb, ctinfo, ct, &dptr, skb->len - dataoff,
+ if (!mangle_sip_packet(skb, ctinfo, ct, dptr, datalen,
buffer, bufflen, POS_CONNECTION_IP4))
return 0;
/* Mangle media port. */
bufflen = sprintf(buffer, "%u", port);
- if (!mangle_sip_packet(skb, ctinfo, ct, &dptr, skb->len - dataoff,
+ if (!mangle_sip_packet(skb, ctinfo, ct, dptr, datalen,
buffer, bufflen, POS_MEDIA))
return 0;
- return mangle_content_len(skb, ctinfo, ct, dptr);
+ return mangle_content_len(skb, ctinfo, ct, dptr, datalen);
}
static void ip_nat_sdp_expect(struct nf_conn *ct,
@@ -242,7 +247,7 @@ static void ip_nat_sdp_expect(struct nf_conn *ct,
static unsigned int ip_nat_sdp(struct sk_buff *skb,
enum ip_conntrack_info ctinfo,
struct nf_conntrack_expect *exp,
- const char *dptr)
+ const char **dptr, unsigned int *datalen)
{
struct nf_conn *ct = exp->master;
enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
@@ -275,7 +280,7 @@ static unsigned int ip_nat_sdp(struct sk_buff *skb,
if (port == 0)
return NF_DROP;
- if (!mangle_sdp(skb, ctinfo, ct, newip, port, dptr)) {
+ if (!mangle_sdp(skb, ctinfo, ct, newip, port, dptr, datalen)) {
nf_ct_unexpect_related(exp);
return NF_DROP;
}
diff --git a/net/netfilter/nf_conntrack_sip.c b/net/netfilter/nf_conntrack_sip.c
index 016e1c1..fa0d559 100644
--- a/net/netfilter/nf_conntrack_sip.c
+++ b/net/netfilter/nf_conntrack_sip.c
@@ -39,13 +39,15 @@ MODULE_PARM_DESC(sip_timeout, "timeout for the master SIP session");
unsigned int (*nf_nat_sip_hook)(struct sk_buff *skb,
enum ip_conntrack_info ctinfo,
struct nf_conn *ct,
- const char **dptr) __read_mostly;
+ const char **dptr,
+ unsigned int *datalen) __read_mostly;
EXPORT_SYMBOL_GPL(nf_nat_sip_hook);
unsigned int (*nf_nat_sdp_hook)(struct sk_buff *skb,
enum ip_conntrack_info ctinfo,
struct nf_conntrack_expect *exp,
- const char *dptr) __read_mostly;
+ const char **dptr,
+ unsigned int *datalen) __read_mostly;
EXPORT_SYMBOL_GPL(nf_nat_sdp_hook);
static int digits_len(const struct nf_conn *, const char *, const char *, int *);
@@ -369,7 +371,7 @@ static int set_expected_rtp(struct sk_buff *skb,
enum ip_conntrack_info ctinfo,
union nf_inet_addr *addr,
__be16 port,
- const char *dptr)
+ const char **dptr, unsigned int *datalen)
{
struct nf_conntrack_expect *exp;
enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
@@ -386,7 +388,7 @@ static int set_expected_rtp(struct sk_buff *skb,
nf_nat_sdp = rcu_dereference(nf_nat_sdp_hook);
if (nf_nat_sdp && ct->status & IPS_NAT_MASK)
- ret = nf_nat_sdp(skb, ctinfo, exp, dptr);
+ ret = nf_nat_sdp(skb, ctinfo, exp, dptr, datalen);
else {
if (nf_ct_expect_related(exp) != 0)
ret = NF_DROP;
@@ -429,7 +431,7 @@ static int sip_help(struct sk_buff *skb,
nf_nat_sip = rcu_dereference(nf_nat_sip_hook);
if (nf_nat_sip && ct->status & IPS_NAT_MASK) {
- if (!nf_nat_sip(skb, ctinfo, ct, &dptr)) {
+ if (!nf_nat_sip(skb, ctinfo, ct, &dptr, &datalen)) {
ret = NF_DROP;
goto out;
}
@@ -466,7 +468,7 @@ static int sip_help(struct sk_buff *skb,
goto out;
}
ret = set_expected_rtp(skb, ct, ctinfo, &addr,
- htons(port), dptr);
+ htons(port), &dptr, &datalen);
}
}
out:
^ permalink raw reply related [flat|nested] 39+ messages in thread* [NETFILTER 11/32]: nf_conntrack_sip: remove redundant function arguments
2008-03-25 14:14 [METFILTER 00/32]: SIP helper update Patrick McHardy
` (9 preceding siblings ...)
2008-03-25 14:15 ` [NETFILTER 10/32]: nf_conntrack_sip: adjust dptr and datalen after packet mangling Patrick McHardy
@ 2008-03-25 14:15 ` Patrick McHardy
2008-03-25 14:15 ` [NETFILTER 12/32]: nf_conntrack_sip: use strlen/strcmp Patrick McHardy
` (21 subsequent siblings)
32 siblings, 0 replies; 39+ messages in thread
From: Patrick McHardy @ 2008-03-25 14:15 UTC (permalink / raw)
To: davem; +Cc: Patrick McHardy, netfilter-devel
[NETFILTER]: nf_conntrack_sip: remove redundant function arguments
The conntrack reference and ctinfo can be derived from the packet.
Signed-off-by: Patrick McHardy <kaber@trash.net>
---
commit 596c3f5c075a54207dcf8dffb108031e736861ba
tree f85551406a7aec725da39f443fd02043af28e5ca
parent cc0d0b162f0e36ddfd0b9fbed58a39a2d1561fb6
author Patrick McHardy <kaber@trash.net> Tue, 25 Mar 2008 12:44:53 +0100
committer Patrick McHardy <kaber@trash.net> Tue, 25 Mar 2008 14:09:54 +0100
include/linux/netfilter/nf_conntrack_sip.h | 7 +---
net/ipv4/netfilter/nf_nat_sip.c | 49 ++++++++++++++--------------
net/netfilter/nf_conntrack_sip.c | 24 ++++++--------
3 files changed, 37 insertions(+), 43 deletions(-)
diff --git a/include/linux/netfilter/nf_conntrack_sip.h b/include/linux/netfilter/nf_conntrack_sip.h
index 9d0dbfb..b94de3d 100644
--- a/include/linux/netfilter/nf_conntrack_sip.h
+++ b/include/linux/netfilter/nf_conntrack_sip.h
@@ -22,15 +22,12 @@ enum sip_header_pos {
};
extern unsigned int (*nf_nat_sip_hook)(struct sk_buff *skb,
- enum ip_conntrack_info ctinfo,
- struct nf_conn *ct,
const char **dptr,
unsigned int *datalen);
extern unsigned int (*nf_nat_sdp_hook)(struct sk_buff *skb,
- enum ip_conntrack_info ctinfo,
- struct nf_conntrack_expect *exp,
const char **dptr,
- unsigned int *datalen);
+ unsigned int *datalen,
+ struct nf_conntrack_expect *exp);
extern int ct_sip_get_info(const struct nf_conn *ct, const char *dptr,
size_t dlen, unsigned int *matchoff,
diff --git a/net/ipv4/netfilter/nf_nat_sip.c b/net/ipv4/netfilter/nf_nat_sip.c
index e77122e..acaa7d4 100644
--- a/net/ipv4/netfilter/nf_nat_sip.c
+++ b/net/ipv4/netfilter/nf_nat_sip.c
@@ -78,11 +78,12 @@ static unsigned int mangle_packet(struct sk_buff *skb,
return 1;
}
-static int map_sip_addr(struct sk_buff *skb, enum ip_conntrack_info ctinfo,
- struct nf_conn *ct,
+static int map_sip_addr(struct sk_buff *skb,
const char **dptr, unsigned int *datalen,
enum sip_header_pos pos, struct addr_map *map)
{
+ enum ip_conntrack_info ctinfo;
+ struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
unsigned int matchlen, matchoff, addrlen;
char *addr;
@@ -109,10 +110,10 @@ static int map_sip_addr(struct sk_buff *skb, enum ip_conntrack_info ctinfo,
}
static unsigned int ip_nat_sip(struct sk_buff *skb,
- enum ip_conntrack_info ctinfo,
- struct nf_conn *ct,
const char **dptr, unsigned int *datalen)
{
+ enum ip_conntrack_info ctinfo;
+ struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
enum sip_header_pos pos;
struct addr_map map;
@@ -134,25 +135,25 @@ static unsigned int ip_nat_sip(struct sk_buff *skb,
else
pos = POS_REQ_URI;
- if (!map_sip_addr(skb, ctinfo, ct, dptr, datalen, pos, &map))
+ if (!map_sip_addr(skb, dptr, datalen, pos, &map))
return NF_DROP;
}
- if (!map_sip_addr(skb, ctinfo, ct, dptr, datalen, POS_FROM, &map) ||
- !map_sip_addr(skb, ctinfo, ct, dptr, datalen, POS_TO, &map) ||
- !map_sip_addr(skb, ctinfo, ct, dptr, datalen, POS_VIA, &map) ||
- !map_sip_addr(skb, ctinfo, ct, dptr, datalen, POS_CONTACT, &map))
+ if (!map_sip_addr(skb, dptr, datalen, POS_FROM, &map) ||
+ !map_sip_addr(skb, dptr, datalen, POS_TO, &map) ||
+ !map_sip_addr(skb, dptr, datalen, POS_VIA, &map) ||
+ !map_sip_addr(skb, dptr, datalen, POS_CONTACT, &map))
return NF_DROP;
return NF_ACCEPT;
}
static unsigned int mangle_sip_packet(struct sk_buff *skb,
- enum ip_conntrack_info ctinfo,
- struct nf_conn *ct,
const char **dptr, unsigned int *datalen,
char *buffer, int bufflen,
enum sip_header_pos pos)
{
+ enum ip_conntrack_info ctinfo;
+ struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
unsigned int matchlen, matchoff;
if (ct_sip_get_info(ct, *dptr, *datalen, &matchoff, &matchlen,
@@ -164,10 +165,10 @@ static unsigned int mangle_sip_packet(struct sk_buff *skb,
}
static int mangle_content_len(struct sk_buff *skb,
- enum ip_conntrack_info ctinfo,
- struct nf_conn *ct,
const char **dptr, unsigned int *datalen)
{
+ enum ip_conntrack_info ctinfo;
+ struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
unsigned int matchoff, matchlen;
char buffer[sizeof("65536")];
int bufflen;
@@ -204,21 +205,21 @@ static unsigned int mangle_sdp(struct sk_buff *skb,
/* Mangle owner and contact info. */
bufflen = sprintf(buffer, "%u.%u.%u.%u", NIPQUAD(newip));
- if (!mangle_sip_packet(skb, ctinfo, ct, dptr, datalen,
- buffer, bufflen, POS_OWNER_IP4))
+ if (!mangle_sip_packet(skb, dptr, datalen, buffer, bufflen,
+ POS_OWNER_IP4))
return 0;
- if (!mangle_sip_packet(skb, ctinfo, ct, dptr, datalen,
- buffer, bufflen, POS_CONNECTION_IP4))
+ if (!mangle_sip_packet(skb, dptr, datalen, buffer, bufflen,
+ POS_CONNECTION_IP4))
return 0;
/* Mangle media port. */
bufflen = sprintf(buffer, "%u", port);
- if (!mangle_sip_packet(skb, ctinfo, ct, dptr, datalen,
- buffer, bufflen, POS_MEDIA))
+ if (!mangle_sip_packet(skb, dptr, datalen, buffer, bufflen,
+ POS_MEDIA))
return 0;
- return mangle_content_len(skb, ctinfo, ct, dptr, datalen);
+ return mangle_content_len(skb, dptr, datalen);
}
static void ip_nat_sdp_expect(struct nf_conn *ct,
@@ -245,11 +246,11 @@ static void ip_nat_sdp_expect(struct nf_conn *ct,
/* So, this packet has hit the connection tracking matching code.
Mangle it, and change the expectation to match the new version. */
static unsigned int ip_nat_sdp(struct sk_buff *skb,
- enum ip_conntrack_info ctinfo,
- struct nf_conntrack_expect *exp,
- const char **dptr, unsigned int *datalen)
+ const char **dptr, unsigned int *datalen,
+ struct nf_conntrack_expect *exp)
{
- struct nf_conn *ct = exp->master;
+ enum ip_conntrack_info ctinfo;
+ struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
__be32 newip;
u_int16_t port;
diff --git a/net/netfilter/nf_conntrack_sip.c b/net/netfilter/nf_conntrack_sip.c
index fa0d559..38e1e7a 100644
--- a/net/netfilter/nf_conntrack_sip.c
+++ b/net/netfilter/nf_conntrack_sip.c
@@ -37,17 +37,14 @@ module_param(sip_timeout, uint, 0600);
MODULE_PARM_DESC(sip_timeout, "timeout for the master SIP session");
unsigned int (*nf_nat_sip_hook)(struct sk_buff *skb,
- enum ip_conntrack_info ctinfo,
- struct nf_conn *ct,
const char **dptr,
unsigned int *datalen) __read_mostly;
EXPORT_SYMBOL_GPL(nf_nat_sip_hook);
unsigned int (*nf_nat_sdp_hook)(struct sk_buff *skb,
- enum ip_conntrack_info ctinfo,
- struct nf_conntrack_expect *exp,
const char **dptr,
- unsigned int *datalen) __read_mostly;
+ unsigned int *datalen,
+ struct nf_conntrack_expect *exp) __read_mostly;
EXPORT_SYMBOL_GPL(nf_nat_sdp_hook);
static int digits_len(const struct nf_conn *, const char *, const char *, int *);
@@ -367,13 +364,12 @@ int ct_sip_get_info(const struct nf_conn *ct,
EXPORT_SYMBOL_GPL(ct_sip_get_info);
static int set_expected_rtp(struct sk_buff *skb,
- struct nf_conn *ct,
- enum ip_conntrack_info ctinfo,
- union nf_inet_addr *addr,
- __be16 port,
- const char **dptr, unsigned int *datalen)
+ const char **dptr, unsigned int *datalen,
+ union nf_inet_addr *addr, __be16 port)
{
struct nf_conntrack_expect *exp;
+ enum ip_conntrack_info ctinfo;
+ struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
int family = ct->tuplehash[!dir].tuple.src.l3num;
int ret;
@@ -388,7 +384,7 @@ static int set_expected_rtp(struct sk_buff *skb,
nf_nat_sdp = rcu_dereference(nf_nat_sdp_hook);
if (nf_nat_sdp && ct->status & IPS_NAT_MASK)
- ret = nf_nat_sdp(skb, ctinfo, exp, dptr, datalen);
+ ret = nf_nat_sdp(skb, dptr, datalen, exp);
else {
if (nf_ct_expect_related(exp) != 0)
ret = NF_DROP;
@@ -431,7 +427,7 @@ static int sip_help(struct sk_buff *skb,
nf_nat_sip = rcu_dereference(nf_nat_sip_hook);
if (nf_nat_sip && ct->status & IPS_NAT_MASK) {
- if (!nf_nat_sip(skb, ctinfo, ct, &dptr, &datalen)) {
+ if (!nf_nat_sip(skb, &dptr, &datalen)) {
ret = NF_DROP;
goto out;
}
@@ -467,8 +463,8 @@ static int sip_help(struct sk_buff *skb,
ret = NF_DROP;
goto out;
}
- ret = set_expected_rtp(skb, ct, ctinfo, &addr,
- htons(port), &dptr, &datalen);
+ ret = set_expected_rtp(skb, &dptr, &datalen,
+ &addr, htons(port));
}
}
out:
^ permalink raw reply related [flat|nested] 39+ messages in thread* [NETFILTER 12/32]: nf_conntrack_sip: use strlen/strcmp
2008-03-25 14:14 [METFILTER 00/32]: SIP helper update Patrick McHardy
` (10 preceding siblings ...)
2008-03-25 14:15 ` [NETFILTER 11/32]: nf_conntrack_sip: remove redundant function arguments Patrick McHardy
@ 2008-03-25 14:15 ` Patrick McHardy
2008-03-25 14:15 ` [NETFILTER 13/32]: nf_conntrack_sip: add seperate SDP header parsing function Patrick McHardy
` (20 subsequent siblings)
32 siblings, 0 replies; 39+ messages in thread
From: Patrick McHardy @ 2008-03-25 14:15 UTC (permalink / raw)
To: davem; +Cc: Patrick McHardy, netfilter-devel
[NETFILTER]: nf_conntrack_sip: use strlen/strcmp
Replace sizeof/memcmp by strlen/strcmp. Use case-insensitive comparison
for SIP methods and the SIP/2.0 string, as specified in RFC 3261.
Signed-off-by: Patrick McHardy <kaber@trash.net>
---
commit 7fc3c23d9817c4086c5bff587d614136ba5dfc80
tree 887b6f2cb2f08cfd94c985960f465c45a82a3b02
parent 596c3f5c075a54207dcf8dffb108031e736861ba
author Patrick McHardy <kaber@trash.net> Tue, 25 Mar 2008 12:44:55 +0100
committer Patrick McHardy <kaber@trash.net> Tue, 25 Mar 2008 14:09:54 +0100
net/ipv4/netfilter/nf_nat_sip.c | 12 ++++++------
net/netfilter/nf_conntrack_sip.c | 12 ++++++------
2 files changed, 12 insertions(+), 12 deletions(-)
diff --git a/net/ipv4/netfilter/nf_nat_sip.c b/net/ipv4/netfilter/nf_nat_sip.c
index acaa7d4..dd1b2d8 100644
--- a/net/ipv4/netfilter/nf_nat_sip.c
+++ b/net/ipv4/netfilter/nf_nat_sip.c
@@ -94,12 +94,12 @@ static int map_sip_addr(struct sk_buff *skb,
if ((matchlen == map->addr[dir].srciplen ||
matchlen == map->addr[dir].srclen) &&
- memcmp(*dptr + matchoff, map->addr[dir].src, matchlen) == 0) {
+ strncmp(*dptr + matchoff, map->addr[dir].src, matchlen) == 0) {
addr = map->addr[!dir].dst;
addrlen = map->addr[!dir].dstlen;
} else if ((matchlen == map->addr[dir].dstiplen ||
matchlen == map->addr[dir].dstlen) &&
- memcmp(*dptr + matchoff, map->addr[dir].dst, matchlen) == 0) {
+ strncmp(*dptr + matchoff, map->addr[dir].dst, matchlen) == 0) {
addr = map->addr[!dir].src;
addrlen = map->addr[!dir].srclen;
} else
@@ -117,20 +117,20 @@ static unsigned int ip_nat_sip(struct sk_buff *skb,
enum sip_header_pos pos;
struct addr_map map;
- if (*datalen < sizeof("SIP/2.0") - 1)
+ if (*datalen < strlen("SIP/2.0"))
return NF_ACCEPT;
addr_map_init(ct, &map);
/* Basic rules: requests and responses. */
- if (strncmp(*dptr, "SIP/2.0", sizeof("SIP/2.0") - 1) != 0) {
+ if (strnicmp(*dptr, "SIP/2.0", strlen("SIP/2.0")) != 0) {
/* 10.2: Constructing the REGISTER Request:
*
* The "userinfo" and "@" components of the SIP URI MUST NOT
* be present.
*/
- if (*datalen >= sizeof("REGISTER") - 1 &&
- strncmp(*dptr, "REGISTER", sizeof("REGISTER") - 1) == 0)
+ if (*datalen >= strlen("REGISTER") &&
+ strnicmp(*dptr, "REGISTER", strlen("REGISTER")) == 0)
pos = POS_REG_REQ_URI;
else
pos = POS_REQ_URI;
diff --git a/net/netfilter/nf_conntrack_sip.c b/net/netfilter/nf_conntrack_sip.c
index 38e1e7a..cf19a70 100644
--- a/net/netfilter/nf_conntrack_sip.c
+++ b/net/netfilter/nf_conntrack_sip.c
@@ -434,15 +434,15 @@ static int sip_help(struct sk_buff *skb,
}
datalen = skb->len - dataoff;
- if (datalen < sizeof("SIP/2.0 200") - 1)
+ if (datalen < strlen("SIP/2.0 200"))
goto out;
/* RTP info only in some SDP pkts */
- if (memcmp(dptr, "INVITE", sizeof("INVITE") - 1) != 0 &&
- memcmp(dptr, "UPDATE", sizeof("UPDATE") - 1) != 0 &&
- memcmp(dptr, "SIP/2.0 180", sizeof("SIP/2.0 180") - 1) != 0 &&
- memcmp(dptr, "SIP/2.0 183", sizeof("SIP/2.0 183") - 1) != 0 &&
- memcmp(dptr, "SIP/2.0 200", sizeof("SIP/2.0 200") - 1) != 0) {
+ if (strnicmp(dptr, "INVITE", strlen("INVITE")) != 0 &&
+ strnicmp(dptr, "UPDATE", strlen("UPDATE")) != 0 &&
+ strnicmp(dptr, "SIP/2.0 180", strlen("SIP/2.0 180")) != 0 &&
+ strnicmp(dptr, "SIP/2.0 183", strlen("SIP/2.0 183")) != 0 &&
+ strnicmp(dptr, "SIP/2.0 200", strlen("SIP/2.0 200")) != 0) {
goto out;
}
/* Get address and port from SDP packet. */
^ permalink raw reply related [flat|nested] 39+ messages in thread* [NETFILTER 13/32]: nf_conntrack_sip: add seperate SDP header parsing function
2008-03-25 14:14 [METFILTER 00/32]: SIP helper update Patrick McHardy
` (11 preceding siblings ...)
2008-03-25 14:15 ` [NETFILTER 12/32]: nf_conntrack_sip: use strlen/strcmp Patrick McHardy
@ 2008-03-25 14:15 ` Patrick McHardy
2008-03-25 14:15 ` [NETFILTER 14/32]: nf_conntrack_sip: kill request URI "header" definitions Patrick McHardy
` (19 subsequent siblings)
32 siblings, 0 replies; 39+ messages in thread
From: Patrick McHardy @ 2008-03-25 14:15 UTC (permalink / raw)
To: davem; +Cc: Patrick McHardy, netfilter-devel
[NETFILTER]: nf_conntrack_sip: add seperate SDP header parsing function
SDP and SIP headers are quite different, SIP can have continuation lines,
leading and trailing whitespace after the colon and is mostly case-insensitive
while SDP headers always begin on a new line and are followed by an equal
sign and the value, without any whitespace.
Introduce new SDP header parsing function and convert all users that used
the SIP header parsing function. This will allow to properly deal with the
special SIP cases in the SIP header parsing function later.
Signed-off-by: Patrick McHardy <kaber@trash.net>
---
commit 3a7cda6054cd6374b0b18b72e71404b5ca7b2155
tree ff4c8e34c71a5151b9122f91b8bb5dc1334cc4f4
parent 7fc3c23d9817c4086c5bff587d614136ba5dfc80
author Patrick McHardy <kaber@trash.net> Tue, 25 Mar 2008 12:44:57 +0100
committer Patrick McHardy <kaber@trash.net> Tue, 25 Mar 2008 14:09:54 +0100
include/linux/netfilter/nf_conntrack_sip.h | 49 ++++++++-
net/ipv4/netfilter/nf_nat_sip.c | 69 ++++++------
net/netfilter/nf_conntrack_sip.c | 159 +++++++++++++++++-----------
3 files changed, 169 insertions(+), 108 deletions(-)
diff --git a/include/linux/netfilter/nf_conntrack_sip.h b/include/linux/netfilter/nf_conntrack_sip.h
index b94de3d..9131cbc 100644
--- a/include/linux/netfilter/nf_conntrack_sip.h
+++ b/include/linux/netfilter/nf_conntrack_sip.h
@@ -13,12 +13,42 @@ enum sip_header_pos {
POS_VIA,
POS_CONTACT,
POS_CONTENT,
- POS_MEDIA,
- POS_OWNER_IP4,
- POS_CONNECTION_IP4,
- POS_OWNER_IP6,
- POS_CONNECTION_IP6,
- POS_SDP_HEADER,
+};
+
+struct sip_header {
+ const char *name;
+ const char *cname;
+ const char *search;
+ unsigned int len;
+ unsigned int clen;
+ unsigned int slen;
+ int (*match_len)(const struct nf_conn *ct,
+ const char *dptr, const char *limit,
+ int *shift);
+};
+
+#define __SIP_HDR(__name, __cname, __search, __match) \
+{ \
+ .name = (__name), \
+ .len = sizeof(__name) - 1, \
+ .cname = (__cname), \
+ .clen = (__cname) ? sizeof(__cname) - 1 : 0, \
+ .search = (__search), \
+ .slen = (__search) ? sizeof(__search) - 1 : 0, \
+ .match_len = (__match), \
+}
+
+#define SDP_HDR(__name, __search, __match) \
+ __SIP_HDR(__name, NULL, __search, __match)
+
+enum sdp_header_types {
+ SDP_HDR_UNSPEC,
+ SDP_HDR_VERSION,
+ SDP_HDR_OWNER_IP4,
+ SDP_HDR_CONNECTION_IP4,
+ SDP_HDR_OWNER_IP6,
+ SDP_HDR_CONNECTION_IP6,
+ SDP_HDR_MEDIA,
};
extern unsigned int (*nf_nat_sip_hook)(struct sk_buff *skb,
@@ -36,5 +66,12 @@ extern int ct_sip_lnlen(const char *line, const char *limit);
extern const char *ct_sip_search(const char *needle, const char *haystack,
size_t needle_len, size_t haystack_len,
int case_sensitive);
+
+extern int ct_sip_get_sdp_header(const struct nf_conn *ct, const char *dptr,
+ unsigned int dataoff, unsigned int datalen,
+ enum sdp_header_types type,
+ enum sdp_header_types term,
+ unsigned int *matchoff, unsigned int *matchlen);
+
#endif /* __KERNEL__ */
#endif /* __NF_CONNTRACK_SIP_H__ */
diff --git a/net/ipv4/netfilter/nf_nat_sip.c b/net/ipv4/netfilter/nf_nat_sip.c
index dd1b2d8..aa8a4f4 100644
--- a/net/ipv4/netfilter/nf_nat_sip.c
+++ b/net/ipv4/netfilter/nf_nat_sip.c
@@ -147,51 +147,46 @@ static unsigned int ip_nat_sip(struct sk_buff *skb,
return NF_ACCEPT;
}
-static unsigned int mangle_sip_packet(struct sk_buff *skb,
- const char **dptr, unsigned int *datalen,
- char *buffer, int bufflen,
- enum sip_header_pos pos)
+static int mangle_content_len(struct sk_buff *skb,
+ const char **dptr, unsigned int *datalen)
{
enum ip_conntrack_info ctinfo;
struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
- unsigned int matchlen, matchoff;
+ unsigned int matchoff, matchlen;
+ char buffer[sizeof("65536")];
+ int buflen, c_len;
+ /* Get actual SDP length */
+ if (ct_sip_get_sdp_header(ct, *dptr, 0, *datalen,
+ SDP_HDR_VERSION, SDP_HDR_UNSPEC,
+ &matchoff, &matchlen) <= 0)
+ return 0;
+ c_len = *datalen - matchoff + strlen("v=");
+
+ /* Now, update SDP length */
if (ct_sip_get_info(ct, *dptr, *datalen, &matchoff, &matchlen,
- pos) <= 0)
+ POS_CONTENT) <= 0)
return 0;
+ buflen = sprintf(buffer, "%u", c_len);
return mangle_packet(skb, dptr, datalen, matchoff, matchlen,
- buffer, bufflen);
+ buffer, buflen);
}
-static int mangle_content_len(struct sk_buff *skb,
- const char **dptr, unsigned int *datalen)
+static unsigned mangle_sdp_packet(struct sk_buff *skb,
+ const char **dptr, unsigned int *datalen,
+ enum sdp_header_types type,
+ char *buffer, int buflen)
{
enum ip_conntrack_info ctinfo;
struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
- unsigned int matchoff, matchlen;
- char buffer[sizeof("65536")];
- int bufflen;
+ unsigned int matchlen, matchoff;
- /* Get actual SDP length */
- if (ct_sip_get_info(ct, *dptr, *datalen, &matchoff,
- &matchlen, POS_SDP_HEADER) > 0) {
-
- /* since ct_sip_get_info() give us a pointer passing 'v='
- we need to add 2 bytes in this count. */
- int c_len = *datalen - matchoff + 2;
-
- /* Now, update SDP length */
- if (ct_sip_get_info(ct, *dptr, *datalen, &matchoff,
- &matchlen, POS_CONTENT) > 0) {
-
- bufflen = sprintf(buffer, "%u", c_len);
- return mangle_packet(skb, dptr, datalen,
- matchoff, matchlen,
- buffer, bufflen);
- }
- }
- return 0;
+ if (ct_sip_get_sdp_header(ct, *dptr, 0, *datalen, type, SDP_HDR_UNSPEC,
+ &matchoff, &matchlen) <= 0)
+ return 0;
+ return mangle_packet(skb, dptr, datalen, matchoff, matchlen,
+ buffer, buflen);
}
static unsigned int mangle_sdp(struct sk_buff *skb,
@@ -205,18 +200,18 @@ static unsigned int mangle_sdp(struct sk_buff *skb,
/* Mangle owner and contact info. */
bufflen = sprintf(buffer, "%u.%u.%u.%u", NIPQUAD(newip));
- if (!mangle_sip_packet(skb, dptr, datalen, buffer, bufflen,
- POS_OWNER_IP4))
+ if (!mangle_sdp_packet(skb, dptr, datalen, SDP_HDR_OWNER_IP4,
+ buffer, bufflen))
return 0;
- if (!mangle_sip_packet(skb, dptr, datalen, buffer, bufflen,
- POS_CONNECTION_IP4))
+ if (!mangle_sdp_packet(skb, dptr, datalen, SDP_HDR_CONNECTION_IP4,
+ buffer, bufflen))
return 0;
/* Mangle media port. */
bufflen = sprintf(buffer, "%u", port);
- if (!mangle_sip_packet(skb, dptr, datalen, buffer, bufflen,
- POS_MEDIA))
+ if (!mangle_sdp_packet(skb, dptr, datalen, SDP_HDR_MEDIA,
+ buffer, bufflen))
return 0;
return mangle_content_len(skb, dptr, datalen);
diff --git a/net/netfilter/nf_conntrack_sip.c b/net/netfilter/nf_conntrack_sip.c
index cf19a70..801fcb3 100644
--- a/net/netfilter/nf_conntrack_sip.c
+++ b/net/netfilter/nf_conntrack_sip.c
@@ -124,66 +124,6 @@ static const struct sip_header_nfo ct_sip_hdrs[] = {
.ln_strlen = sizeof(":") - 1,
.match_len = skp_digits_len
},
- [POS_MEDIA] = { /* SDP media info */
- .case_sensitive = 1,
- .lname = "\nm=",
- .lnlen = sizeof("\nm=") - 1,
- .sname = "\rm=",
- .snlen = sizeof("\rm=") - 1,
- .ln_str = "audio ",
- .ln_strlen = sizeof("audio ") - 1,
- .match_len = digits_len
- },
- [POS_OWNER_IP4] = { /* SDP owner address*/
- .case_sensitive = 1,
- .lname = "\no=",
- .lnlen = sizeof("\no=") - 1,
- .sname = "\ro=",
- .snlen = sizeof("\ro=") - 1,
- .ln_str = "IN IP4 ",
- .ln_strlen = sizeof("IN IP4 ") - 1,
- .match_len = epaddr_len
- },
- [POS_CONNECTION_IP4] = {/* SDP connection info */
- .case_sensitive = 1,
- .lname = "\nc=",
- .lnlen = sizeof("\nc=") - 1,
- .sname = "\rc=",
- .snlen = sizeof("\rc=") - 1,
- .ln_str = "IN IP4 ",
- .ln_strlen = sizeof("IN IP4 ") - 1,
- .match_len = epaddr_len
- },
- [POS_OWNER_IP6] = { /* SDP owner address*/
- .case_sensitive = 1,
- .lname = "\no=",
- .lnlen = sizeof("\no=") - 1,
- .sname = "\ro=",
- .snlen = sizeof("\ro=") - 1,
- .ln_str = "IN IP6 ",
- .ln_strlen = sizeof("IN IP6 ") - 1,
- .match_len = epaddr_len
- },
- [POS_CONNECTION_IP6] = {/* SDP connection info */
- .case_sensitive = 1,
- .lname = "\nc=",
- .lnlen = sizeof("\nc=") - 1,
- .sname = "\rc=",
- .snlen = sizeof("\rc=") - 1,
- .ln_str = "IN IP6 ",
- .ln_strlen = sizeof("IN IP6 ") - 1,
- .match_len = epaddr_len
- },
- [POS_SDP_HEADER] = { /* SDP version header */
- .case_sensitive = 1,
- .lname = "\nv=",
- .lnlen = sizeof("\nv=") - 1,
- .sname = "\rv=",
- .snlen = sizeof("\rv=") - 1,
- .ln_str = "=",
- .ln_strlen = sizeof("=") - 1,
- .match_len = digits_len
- }
};
/* get line length until first CR or LF seen. */
@@ -363,6 +303,92 @@ int ct_sip_get_info(const struct nf_conn *ct,
}
EXPORT_SYMBOL_GPL(ct_sip_get_info);
+/* SDP header parsing: a SDP session description contains an ordered set of
+ * headers, starting with a section containing general session parameters,
+ * optionally followed by multiple media descriptions.
+ *
+ * SDP headers always start at the beginning of a line. According to RFC 2327:
+ * "The sequence CRLF (0x0d0a) is used to end a record, although parsers should
+ * be tolerant and also accept records terminated with a single newline
+ * character". We handle both cases.
+ */
+static const struct sip_header ct_sdp_hdrs[] = {
+ [SDP_HDR_VERSION] = SDP_HDR("v=", NULL, digits_len),
+ [SDP_HDR_OWNER_IP4] = SDP_HDR("o=", "IN IP4 ", epaddr_len),
+ [SDP_HDR_CONNECTION_IP4] = SDP_HDR("c=", "IN IP4 ", epaddr_len),
+ [SDP_HDR_OWNER_IP6] = SDP_HDR("o=", "IN IP6 ", epaddr_len),
+ [SDP_HDR_CONNECTION_IP6] = SDP_HDR("c=", "IN IP6 ", epaddr_len),
+ [SDP_HDR_MEDIA] = SDP_HDR("m=", "audio ", digits_len),
+};
+
+/* Linear string search within SDP header values */
+static const char *ct_sdp_header_search(const char *dptr, const char *limit,
+ const char *needle, unsigned int len)
+{
+ for (limit -= len; dptr < limit; dptr++) {
+ if (*dptr == '\r' || *dptr == '\n')
+ break;
+ if (strncmp(dptr, needle, len) == 0)
+ return dptr;
+ }
+ return NULL;
+}
+
+/* Locate a SDP header (optionally a substring within the header value),
+ * optionally stopping at the first occurence of the term header, parse
+ * it and return the offset and length of the data we're interested in.
+ */
+int ct_sip_get_sdp_header(const struct nf_conn *ct, const char *dptr,
+ unsigned int dataoff, unsigned int datalen,
+ enum sdp_header_types type,
+ enum sdp_header_types term,
+ unsigned int *matchoff, unsigned int *matchlen)
+{
+ const struct sip_header *hdr = &ct_sdp_hdrs[type];
+ const struct sip_header *thdr = &ct_sdp_hdrs[term];
+ const char *start = dptr, *limit = dptr + datalen;
+ int shift = 0;
+
+ for (dptr += dataoff; dptr < limit; dptr++) {
+ /* Find beginning of line */
+ if (*dptr != '\r' && *dptr != '\n')
+ continue;
+ if (++dptr >= limit)
+ break;
+ if (*(dptr - 1) == '\r' && *dptr == '\n') {
+ if (++dptr >= limit)
+ break;
+ }
+
+ if (term != SDP_HDR_UNSPEC &&
+ limit - dptr >= thdr->len &&
+ strnicmp(dptr, thdr->name, thdr->len) == 0)
+ break;
+ else if (limit - dptr >= hdr->len &&
+ strnicmp(dptr, hdr->name, hdr->len) == 0)
+ dptr += hdr->len;
+ else
+ continue;
+
+ *matchoff = dptr - start;
+ if (hdr->search) {
+ dptr = ct_sdp_header_search(dptr, limit, hdr->search,
+ hdr->slen);
+ if (!dptr)
+ return -1;
+ dptr += hdr->slen;
+ }
+
+ *matchlen = hdr->match_len(ct, dptr, limit, &shift);
+ if (!*matchlen)
+ return -1;
+ *matchoff = dptr - start + shift;
+ return 1;
+ }
+ return 0;
+}
+EXPORT_SYMBOL_GPL(ct_sip_get_sdp_header);
+
static int set_expected_rtp(struct sk_buff *skb,
const char **dptr, unsigned int *datalen,
union nf_inet_addr *addr, __be16 port)
@@ -408,7 +434,7 @@ static int sip_help(struct sk_buff *skb,
int ret = NF_ACCEPT;
unsigned int matchoff, matchlen;
u_int16_t port;
- enum sip_header_pos pos;
+ enum sdp_header_types type;
typeof(nf_nat_sip_hook) nf_nat_sip;
/* No Data ? */
@@ -446,8 +472,10 @@ static int sip_help(struct sk_buff *skb,
goto out;
}
/* Get address and port from SDP packet. */
- pos = family == AF_INET ? POS_CONNECTION_IP4 : POS_CONNECTION_IP6;
- if (ct_sip_get_info(ct, dptr, datalen, &matchoff, &matchlen, pos) > 0) {
+ type = family == AF_INET ? SDP_HDR_CONNECTION_IP4 :
+ SDP_HDR_CONNECTION_IP6;
+ if (ct_sip_get_sdp_header(ct, dptr, 0, datalen, type, SDP_HDR_UNSPEC,
+ &matchoff, &matchlen) > 0) {
/* We'll drop only if there are parse problems. */
if (!parse_addr(ct, dptr + matchoff, NULL, &addr,
@@ -455,8 +483,9 @@ static int sip_help(struct sk_buff *skb,
ret = NF_DROP;
goto out;
}
- if (ct_sip_get_info(ct, dptr, datalen, &matchoff, &matchlen,
- POS_MEDIA) > 0) {
+ if (ct_sip_get_sdp_header(ct, dptr, 0, datalen,
+ SDP_HDR_MEDIA, SDP_HDR_UNSPEC,
+ &matchoff, &matchlen) > 0) {
port = simple_strtoul(dptr + matchoff, NULL, 10);
if (port < 1024) {
^ permalink raw reply related [flat|nested] 39+ messages in thread* [NETFILTER 14/32]: nf_conntrack_sip: kill request URI "header" definitions
2008-03-25 14:14 [METFILTER 00/32]: SIP helper update Patrick McHardy
` (12 preceding siblings ...)
2008-03-25 14:15 ` [NETFILTER 13/32]: nf_conntrack_sip: add seperate SDP header parsing function Patrick McHardy
@ 2008-03-25 14:15 ` Patrick McHardy
2008-03-25 14:15 ` [NETFILTER 15/32]: nf_conntrack_sip: parse SIP headers properly Patrick McHardy
` (18 subsequent siblings)
32 siblings, 0 replies; 39+ messages in thread
From: Patrick McHardy @ 2008-03-25 14:15 UTC (permalink / raw)
To: davem; +Cc: Patrick McHardy, netfilter-devel
[NETFILTER]: nf_conntrack_sip: kill request URI "header" definitions
The request URI is not a header and needs to be treated differently than
real SIP headers. Add a seperate function for parsing it and get rid of
the POS_REQ_URI/POS_REG_REQ_URI definitions.
Signed-off-by: Patrick McHardy <kaber@trash.net>
---
commit 6b8ae4462dcdaf5c0e28ea5750f391efb738fab1
tree a59c883431a99d5eb65b0ce5039f5cccda8631ab
parent 3a7cda6054cd6374b0b18b72e71404b5ca7b2155
author Patrick McHardy <kaber@trash.net> Tue, 25 Mar 2008 12:44:58 +0100
committer Patrick McHardy <kaber@trash.net> Tue, 25 Mar 2008 14:09:55 +0100
include/linux/netfilter/nf_conntrack_sip.h | 5 +-
net/ipv4/netfilter/nf_nat_sip.c | 46 +++++++++++---------
net/netfilter/nf_conntrack_sip.c | 64 ++++++++++++++++++++++------
3 files changed, 77 insertions(+), 38 deletions(-)
diff --git a/include/linux/netfilter/nf_conntrack_sip.h b/include/linux/netfilter/nf_conntrack_sip.h
index 9131cbc..480b26f 100644
--- a/include/linux/netfilter/nf_conntrack_sip.h
+++ b/include/linux/netfilter/nf_conntrack_sip.h
@@ -6,8 +6,6 @@
#define SIP_TIMEOUT 3600
enum sip_header_pos {
- POS_REG_REQ_URI,
- POS_REQ_URI,
POS_FROM,
POS_TO,
POS_VIA,
@@ -59,6 +57,9 @@ extern unsigned int (*nf_nat_sdp_hook)(struct sk_buff *skb,
unsigned int *datalen,
struct nf_conntrack_expect *exp);
+extern int ct_sip_parse_request(const struct nf_conn *ct,
+ const char *dptr, unsigned int datalen,
+ unsigned int *matchoff, unsigned int *matchlen);
extern int ct_sip_get_info(const struct nf_conn *ct, const char *dptr,
size_t dlen, unsigned int *matchoff,
unsigned int *matchlen, enum sip_header_pos pos);
diff --git a/net/ipv4/netfilter/nf_nat_sip.c b/net/ipv4/netfilter/nf_nat_sip.c
index aa8a4f4..60151b5 100644
--- a/net/ipv4/netfilter/nf_nat_sip.c
+++ b/net/ipv4/netfilter/nf_nat_sip.c
@@ -78,20 +78,17 @@ static unsigned int mangle_packet(struct sk_buff *skb,
return 1;
}
-static int map_sip_addr(struct sk_buff *skb,
- const char **dptr, unsigned int *datalen,
- enum sip_header_pos pos, struct addr_map *map)
+static int map_addr(struct sk_buff *skb,
+ const char **dptr, unsigned int *datalen,
+ unsigned int matchoff, unsigned int matchlen,
+ struct addr_map *map)
{
enum ip_conntrack_info ctinfo;
- struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
+ struct nf_conn *ct __maybe_unused = nf_ct_get(skb, &ctinfo);
enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
- unsigned int matchlen, matchoff, addrlen;
+ unsigned int addrlen;
char *addr;
- if (ct_sip_get_info(ct, *dptr, *datalen, &matchoff, &matchlen,
- pos) <= 0)
- return 1;
-
if ((matchlen == map->addr[dir].srciplen ||
matchlen == map->addr[dir].srclen) &&
strncmp(*dptr + matchoff, map->addr[dir].src, matchlen) == 0) {
@@ -109,13 +106,27 @@ static int map_sip_addr(struct sk_buff *skb,
addr, addrlen);
}
+static int map_sip_addr(struct sk_buff *skb,
+ const char **dptr, unsigned int *datalen,
+ enum sip_header_pos pos, struct addr_map *map)
+{
+ enum ip_conntrack_info ctinfo;
+ struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
+ unsigned int matchlen, matchoff;
+
+ if (ct_sip_get_info(ct, *dptr, *datalen, &matchoff, &matchlen,
+ pos) <= 0)
+ return 1;
+ return map_addr(skb, dptr, datalen, matchoff, matchlen, map);
+}
+
static unsigned int ip_nat_sip(struct sk_buff *skb,
const char **dptr, unsigned int *datalen)
{
enum ip_conntrack_info ctinfo;
struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
- enum sip_header_pos pos;
struct addr_map map;
+ unsigned int matchoff, matchlen;
if (*datalen < strlen("SIP/2.0"))
return NF_ACCEPT;
@@ -124,18 +135,9 @@ static unsigned int ip_nat_sip(struct sk_buff *skb,
/* Basic rules: requests and responses. */
if (strnicmp(*dptr, "SIP/2.0", strlen("SIP/2.0")) != 0) {
- /* 10.2: Constructing the REGISTER Request:
- *
- * The "userinfo" and "@" components of the SIP URI MUST NOT
- * be present.
- */
- if (*datalen >= strlen("REGISTER") &&
- strnicmp(*dptr, "REGISTER", strlen("REGISTER")) == 0)
- pos = POS_REG_REQ_URI;
- else
- pos = POS_REQ_URI;
-
- if (!map_sip_addr(skb, dptr, datalen, pos, &map))
+ if (ct_sip_parse_request(ct, *dptr, *datalen,
+ &matchoff, &matchlen) > 0 &&
+ !map_addr(skb, dptr, datalen, matchoff, matchlen, &map))
return NF_DROP;
}
diff --git a/net/netfilter/nf_conntrack_sip.c b/net/netfilter/nf_conntrack_sip.c
index 801fcb3..bb43961 100644
--- a/net/netfilter/nf_conntrack_sip.c
+++ b/net/netfilter/nf_conntrack_sip.c
@@ -65,20 +65,6 @@ struct sip_header_nfo {
};
static const struct sip_header_nfo ct_sip_hdrs[] = {
- [POS_REG_REQ_URI] = { /* SIP REGISTER request URI */
- .lname = "sip:",
- .lnlen = sizeof("sip:") - 1,
- .ln_str = ":",
- .ln_strlen = sizeof(":") - 1,
- .match_len = epaddr_len,
- },
- [POS_REQ_URI] = { /* SIP request URI */
- .lname = "sip:",
- .lnlen = sizeof("sip:") - 1,
- .ln_str = "@",
- .ln_strlen = sizeof("@") - 1,
- .match_len = epaddr_len,
- },
[POS_FROM] = { /* SIP From header */
.lname = "From:",
.lnlen = sizeof("From:") - 1,
@@ -164,6 +150,18 @@ const char *ct_sip_search(const char *needle, const char *haystack,
}
EXPORT_SYMBOL_GPL(ct_sip_search);
+static int string_len(const struct nf_conn *ct, const char *dptr,
+ const char *limit, int *shift)
+{
+ int len = 0;
+
+ while (dptr < limit && isalpha(*dptr)) {
+ dptr++;
+ len++;
+ }
+ return len;
+}
+
static int digits_len(const struct nf_conn *ct, const char *dptr,
const char *limit, int *shift)
{
@@ -258,6 +256,44 @@ static int skp_epaddr_len(const struct nf_conn *ct, const char *dptr,
return epaddr_len(ct, dptr, limit, shift);
}
+/* Parse a SIP request line of the form:
+ *
+ * Request-Line = Method SP Request-URI SP SIP-Version CRLF
+ *
+ * and return the offset and length of the address contained in the Request-URI.
+ */
+int ct_sip_parse_request(const struct nf_conn *ct,
+ const char *dptr, unsigned int datalen,
+ unsigned int *matchoff, unsigned int *matchlen)
+{
+ const char *start = dptr, *limit = dptr + datalen;
+ unsigned int mlen;
+ int shift = 0;
+
+ /* Skip method and following whitespace */
+ mlen = string_len(ct, dptr, limit, NULL);
+ if (!mlen)
+ return 0;
+ dptr += mlen;
+ if (++dptr >= limit)
+ return 0;
+
+ /* Find SIP URI */
+ limit -= strlen("sip:");
+ for (; dptr < limit; dptr++) {
+ if (*dptr == '\r' || *dptr == '\n')
+ return -1;
+ if (strnicmp(dptr, "sip:", strlen("sip:")) == 0)
+ break;
+ }
+ *matchlen = skp_epaddr_len(ct, dptr, limit, &shift);
+ if (!*matchlen)
+ return 0;
+ *matchoff = dptr - start + shift;
+ return 1;
+}
+EXPORT_SYMBOL_GPL(ct_sip_parse_request);
+
/* Returns 0 if not found, -1 error parsing. */
int ct_sip_get_info(const struct nf_conn *ct,
const char *dptr, size_t dlen,
^ permalink raw reply related [flat|nested] 39+ messages in thread* [NETFILTER 15/32]: nf_conntrack_sip: parse SIP headers properly
2008-03-25 14:14 [METFILTER 00/32]: SIP helper update Patrick McHardy
` (13 preceding siblings ...)
2008-03-25 14:15 ` [NETFILTER 14/32]: nf_conntrack_sip: kill request URI "header" definitions Patrick McHardy
@ 2008-03-25 14:15 ` Patrick McHardy
2008-03-25 14:15 ` [NETFILTER 16/32]: nf_conntrack_sip: introduce SIP-URI parsing helper Patrick McHardy
` (17 subsequent siblings)
32 siblings, 0 replies; 39+ messages in thread
From: Patrick McHardy @ 2008-03-25 14:15 UTC (permalink / raw)
To: davem; +Cc: Patrick McHardy, netfilter-devel
[NETFILTER]: nf_conntrack_sip: parse SIP headers properly
Introduce new function for SIP header parsing that properly deals with
continuation lines and whitespace in headers and use it.
Signed-off-by: Patrick McHardy <kaber@trash.net>
---
commit 0b864cf59cb6bfb74677aa9c631b7c8df53016a2
tree fa5dc291dbd565fc7167a3e2415e54f3aecdfd04
parent 6b8ae4462dcdaf5c0e28ea5750f391efb738fab1
author Patrick McHardy <kaber@trash.net> Tue, 25 Mar 2008 12:45:00 +0100
committer Patrick McHardy <kaber@trash.net> Tue, 25 Mar 2008 14:09:55 +0100
include/linux/netfilter/nf_conntrack_sip.h | 30 ++-
net/ipv4/netfilter/nf_nat_sip.c | 18 +-
net/netfilter/nf_conntrack_sip.c | 271 +++++++++++++---------------
3 files changed, 151 insertions(+), 168 deletions(-)
diff --git a/include/linux/netfilter/nf_conntrack_sip.h b/include/linux/netfilter/nf_conntrack_sip.h
index 480b26f..ccc7014 100644
--- a/include/linux/netfilter/nf_conntrack_sip.h
+++ b/include/linux/netfilter/nf_conntrack_sip.h
@@ -5,14 +5,6 @@
#define SIP_PORT 5060
#define SIP_TIMEOUT 3600
-enum sip_header_pos {
- POS_FROM,
- POS_TO,
- POS_VIA,
- POS_CONTACT,
- POS_CONTENT,
-};
-
struct sip_header {
const char *name;
const char *cname;
@@ -36,9 +28,20 @@ struct sip_header {
.match_len = (__match), \
}
+#define SIP_HDR(__name, __cname, __search, __match) \
+ __SIP_HDR(__name, __cname, __search, __match)
+
#define SDP_HDR(__name, __search, __match) \
__SIP_HDR(__name, NULL, __search, __match)
+enum sip_header_types {
+ SIP_HDR_FROM,
+ SIP_HDR_TO,
+ SIP_HDR_CONTACT,
+ SIP_HDR_VIA,
+ SIP_HDR_CONTENT_LENGTH,
+};
+
enum sdp_header_types {
SDP_HDR_UNSPEC,
SDP_HDR_VERSION,
@@ -60,13 +63,10 @@ extern unsigned int (*nf_nat_sdp_hook)(struct sk_buff *skb,
extern int ct_sip_parse_request(const struct nf_conn *ct,
const char *dptr, unsigned int datalen,
unsigned int *matchoff, unsigned int *matchlen);
-extern int ct_sip_get_info(const struct nf_conn *ct, const char *dptr,
- size_t dlen, unsigned int *matchoff,
- unsigned int *matchlen, enum sip_header_pos pos);
-extern int ct_sip_lnlen(const char *line, const char *limit);
-extern const char *ct_sip_search(const char *needle, const char *haystack,
- size_t needle_len, size_t haystack_len,
- int case_sensitive);
+extern int ct_sip_get_header(const struct nf_conn *ct, const char *dptr,
+ unsigned int dataoff, unsigned int datalen,
+ enum sip_header_types type,
+ unsigned int *matchoff, unsigned int *matchlen);
extern int ct_sip_get_sdp_header(const struct nf_conn *ct, const char *dptr,
unsigned int dataoff, unsigned int datalen,
diff --git a/net/ipv4/netfilter/nf_nat_sip.c b/net/ipv4/netfilter/nf_nat_sip.c
index 60151b5..c13e438 100644
--- a/net/ipv4/netfilter/nf_nat_sip.c
+++ b/net/ipv4/netfilter/nf_nat_sip.c
@@ -108,14 +108,14 @@ static int map_addr(struct sk_buff *skb,
static int map_sip_addr(struct sk_buff *skb,
const char **dptr, unsigned int *datalen,
- enum sip_header_pos pos, struct addr_map *map)
+ enum sip_header_types type, struct addr_map *map)
{
enum ip_conntrack_info ctinfo;
struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
unsigned int matchlen, matchoff;
- if (ct_sip_get_info(ct, *dptr, *datalen, &matchoff, &matchlen,
- pos) <= 0)
+ if (ct_sip_get_header(ct, *dptr, 0, *datalen, type,
+ &matchoff, &matchlen) <= 0)
return 1;
return map_addr(skb, dptr, datalen, matchoff, matchlen, map);
}
@@ -141,10 +141,10 @@ static unsigned int ip_nat_sip(struct sk_buff *skb,
return NF_DROP;
}
- if (!map_sip_addr(skb, dptr, datalen, POS_FROM, &map) ||
- !map_sip_addr(skb, dptr, datalen, POS_TO, &map) ||
- !map_sip_addr(skb, dptr, datalen, POS_VIA, &map) ||
- !map_sip_addr(skb, dptr, datalen, POS_CONTACT, &map))
+ if (!map_sip_addr(skb, dptr, datalen, SIP_HDR_FROM, &map) ||
+ !map_sip_addr(skb, dptr, datalen, SIP_HDR_TO, &map) ||
+ !map_sip_addr(skb, dptr, datalen, SIP_HDR_VIA, &map) ||
+ !map_sip_addr(skb, dptr, datalen, SIP_HDR_CONTACT, &map))
return NF_DROP;
return NF_ACCEPT;
}
@@ -166,8 +166,8 @@ static int mangle_content_len(struct sk_buff *skb,
c_len = *datalen - matchoff + strlen("v=");
/* Now, update SDP length */
- if (ct_sip_get_info(ct, *dptr, *datalen, &matchoff, &matchlen,
- POS_CONTENT) <= 0)
+ if (ct_sip_get_header(ct, *dptr, 0, *datalen, SIP_HDR_CONTENT_LENGTH,
+ &matchoff, &matchlen) <= 0)
return 0;
buflen = sprintf(buffer, "%u", c_len);
diff --git a/net/netfilter/nf_conntrack_sip.c b/net/netfilter/nf_conntrack_sip.c
index bb43961..cbc9159 100644
--- a/net/netfilter/nf_conntrack_sip.c
+++ b/net/netfilter/nf_conntrack_sip.c
@@ -47,109 +47,6 @@ unsigned int (*nf_nat_sdp_hook)(struct sk_buff *skb,
struct nf_conntrack_expect *exp) __read_mostly;
EXPORT_SYMBOL_GPL(nf_nat_sdp_hook);
-static int digits_len(const struct nf_conn *, const char *, const char *, int *);
-static int epaddr_len(const struct nf_conn *, const char *, const char *, int *);
-static int skp_digits_len(const struct nf_conn *, const char *, const char *, int *);
-static int skp_epaddr_len(const struct nf_conn *, const char *, const char *, int *);
-
-struct sip_header_nfo {
- const char *lname;
- const char *sname;
- const char *ln_str;
- size_t lnlen;
- size_t snlen;
- size_t ln_strlen;
- int case_sensitive;
- int (*match_len)(const struct nf_conn *, const char *,
- const char *, int *);
-};
-
-static const struct sip_header_nfo ct_sip_hdrs[] = {
- [POS_FROM] = { /* SIP From header */
- .lname = "From:",
- .lnlen = sizeof("From:") - 1,
- .sname = "\r\nf:",
- .snlen = sizeof("\r\nf:") - 1,
- .ln_str = "sip:",
- .ln_strlen = sizeof("sip:") - 1,
- .match_len = skp_epaddr_len,
- },
- [POS_TO] = { /* SIP To header */
- .lname = "To:",
- .lnlen = sizeof("To:") - 1,
- .sname = "\r\nt:",
- .snlen = sizeof("\r\nt:") - 1,
- .ln_str = "sip:",
- .ln_strlen = sizeof("sip:") - 1,
- .match_len = skp_epaddr_len
- },
- [POS_VIA] = { /* SIP Via header */
- .lname = "Via:",
- .lnlen = sizeof("Via:") - 1,
- .sname = "\r\nv:",
- .snlen = sizeof("\r\nv:") - 1, /* rfc3261 "\r\n" */
- .ln_str = "UDP ",
- .ln_strlen = sizeof("UDP ") - 1,
- .match_len = epaddr_len,
- },
- [POS_CONTACT] = { /* SIP Contact header */
- .lname = "Contact:",
- .lnlen = sizeof("Contact:") - 1,
- .sname = "\r\nm:",
- .snlen = sizeof("\r\nm:") - 1,
- .ln_str = "sip:",
- .ln_strlen = sizeof("sip:") - 1,
- .match_len = skp_epaddr_len
- },
- [POS_CONTENT] = { /* SIP Content length header */
- .lname = "Content-Length:",
- .lnlen = sizeof("Content-Length:") - 1,
- .sname = "\r\nl:",
- .snlen = sizeof("\r\nl:") - 1,
- .ln_str = ":",
- .ln_strlen = sizeof(":") - 1,
- .match_len = skp_digits_len
- },
-};
-
-/* get line length until first CR or LF seen. */
-int ct_sip_lnlen(const char *line, const char *limit)
-{
- const char *k = line;
-
- while ((line < limit) && (*line == '\r' || *line == '\n'))
- line++;
-
- while (line < limit) {
- if (*line == '\r' || *line == '\n')
- break;
- line++;
- }
- return line - k;
-}
-EXPORT_SYMBOL_GPL(ct_sip_lnlen);
-
-/* Linear string search, case sensitive. */
-const char *ct_sip_search(const char *needle, const char *haystack,
- size_t needle_len, size_t haystack_len,
- int case_sensitive)
-{
- const char *limit = haystack + (haystack_len - needle_len);
-
- while (haystack < limit) {
- if (case_sensitive) {
- if (strncmp(haystack, needle, needle_len) == 0)
- return haystack;
- } else {
- if (strnicmp(haystack, needle, needle_len) == 0)
- return haystack;
- }
- haystack++;
- }
- return NULL;
-}
-EXPORT_SYMBOL_GPL(ct_sip_search);
-
static int string_len(const struct nf_conn *ct, const char *dptr,
const char *limit, int *shift)
{
@@ -173,16 +70,6 @@ static int digits_len(const struct nf_conn *ct, const char *dptr,
return len;
}
-/* get digits length, skipping blank spaces. */
-static int skp_digits_len(const struct nf_conn *ct, const char *dptr,
- const char *limit, int *shift)
-{
- for (; dptr < limit && *dptr == ' '; dptr++)
- (*shift)++;
-
- return digits_len(ct, dptr, limit, shift);
-}
-
static int parse_addr(const struct nf_conn *ct, const char *cp,
const char **endp, union nf_inet_addr *addr,
const char *limit)
@@ -294,50 +181,146 @@ int ct_sip_parse_request(const struct nf_conn *ct,
}
EXPORT_SYMBOL_GPL(ct_sip_parse_request);
-/* Returns 0 if not found, -1 error parsing. */
-int ct_sip_get_info(const struct nf_conn *ct,
- const char *dptr, size_t dlen,
- unsigned int *matchoff,
- unsigned int *matchlen,
- enum sip_header_pos pos)
+/* SIP header parsing: SIP headers are located at the beginning of a line, but
+ * may span several lines, in which case the continuation lines begin with a
+ * whitespace character. RFC 2543 allows lines to be terminated with CR, LF or
+ * CRLF, RFC 3261 allows only CRLF, we support both.
+ *
+ * Headers are followed by (optionally) whitespace, a colon, again (optionally)
+ * whitespace and the values. Whitespace in this context means any amount of
+ * tabs, spaces and continuation lines, which are treated as a single whitespace
+ * character.
+ */
+static const struct sip_header ct_sip_hdrs[] = {
+ [SIP_HDR_FROM] = SIP_HDR("From", "f", "sip:", skp_epaddr_len),
+ [SIP_HDR_TO] = SIP_HDR("To", "t", "sip:", skp_epaddr_len),
+ [SIP_HDR_CONTACT] = SIP_HDR("Contact", "m", "sip:", skp_epaddr_len),
+ [SIP_HDR_VIA] = SIP_HDR("Via", "v", "UDP ", epaddr_len),
+ [SIP_HDR_CONTENT_LENGTH] = SIP_HDR("Content-Length", "l", NULL, digits_len),
+};
+
+static const char *sip_follow_continuation(const char *dptr, const char *limit)
{
- const struct sip_header_nfo *hnfo = &ct_sip_hdrs[pos];
- const char *limit, *aux, *k = dptr;
- int shift = 0;
+ /* Walk past newline */
+ if (++dptr >= limit)
+ return NULL;
+
+ /* Skip '\n' in CR LF */
+ if (*(dptr - 1) == '\r' && *dptr == '\n') {
+ if (++dptr >= limit)
+ return NULL;
+ }
+
+ /* Continuation line? */
+ if (*dptr != ' ' && *dptr != '\t')
+ return NULL;
+
+ /* skip leading whitespace */
+ for (; dptr < limit; dptr++) {
+ if (*dptr != ' ' && *dptr != '\t')
+ break;
+ }
+ return dptr;
+}
+
+static const char *sip_skip_whitespace(const char *dptr, const char *limit)
+{
+ for (; dptr < limit; dptr++) {
+ if (*dptr == ' ')
+ continue;
+ if (*dptr != '\r' && *dptr != '\n')
+ break;
+ dptr = sip_follow_continuation(dptr, limit);
+ if (dptr == NULL)
+ return NULL;
+ }
+ return dptr;
+}
- limit = dptr + (dlen - hnfo->lnlen);
+/* Search within a SIP header value, dealing with continuation lines */
+static const char *ct_sip_header_search(const char *dptr, const char *limit,
+ const char *needle, unsigned int len)
+{
+ for (limit -= len; dptr < limit; dptr++) {
+ if (*dptr == '\r' || *dptr == '\n') {
+ dptr = sip_follow_continuation(dptr, limit);
+ if (dptr == NULL)
+ break;
+ continue;
+ }
- while (dptr < limit) {
- if ((strncmp(dptr, hnfo->lname, hnfo->lnlen) != 0) &&
- (hnfo->sname == NULL ||
- strncmp(dptr, hnfo->sname, hnfo->snlen) != 0)) {
- dptr++;
+ if (strnicmp(dptr, needle, len) == 0)
+ return dptr;
+ }
+ return NULL;
+}
+
+int ct_sip_get_header(const struct nf_conn *ct, const char *dptr,
+ unsigned int dataoff, unsigned int datalen,
+ enum sip_header_types type,
+ unsigned int *matchoff, unsigned int *matchlen)
+{
+ const struct sip_header *hdr = &ct_sip_hdrs[type];
+ const char *start = dptr, *limit = dptr + datalen;
+ int shift = 0;
+
+ for (dptr += dataoff; dptr < limit; dptr++) {
+ /* Find beginning of line */
+ if (*dptr != '\r' && *dptr != '\n')
continue;
+ if (++dptr >= limit)
+ break;
+ if (*(dptr - 1) == '\r' && *dptr == '\n') {
+ if (++dptr >= limit)
+ break;
}
- aux = ct_sip_search(hnfo->ln_str, dptr, hnfo->ln_strlen,
- ct_sip_lnlen(dptr, limit),
- hnfo->case_sensitive);
- if (!aux) {
- pr_debug("'%s' not found in '%s'.\n", hnfo->ln_str,
- hnfo->lname);
- return -1;
+
+ /* Skip continuation lines */
+ if (*dptr == ' ' || *dptr == '\t')
+ continue;
+
+ /* Find header. Compact headers must be followed by a
+ * non-alphabetic character to avoid mismatches. */
+ if (limit - dptr >= hdr->len &&
+ strnicmp(dptr, hdr->name, hdr->len) == 0)
+ dptr += hdr->len;
+ else if (hdr->cname && limit - dptr >= hdr->clen + 1 &&
+ strnicmp(dptr, hdr->cname, hdr->clen) == 0 &&
+ !isalpha(*(dptr + hdr->clen + 1)))
+ dptr += hdr->clen;
+ else
+ continue;
+
+ /* Find and skip colon */
+ dptr = sip_skip_whitespace(dptr, limit);
+ if (dptr == NULL)
+ break;
+ if (*dptr != ':' || ++dptr >= limit)
+ break;
+
+ /* Skip whitespace after colon */
+ dptr = sip_skip_whitespace(dptr, limit);
+ if (dptr == NULL)
+ break;
+
+ *matchoff = dptr - start;
+ if (hdr->search) {
+ dptr = ct_sip_header_search(dptr, limit, hdr->search,
+ hdr->slen);
+ if (!dptr)
+ return -1;
+ dptr += hdr->slen;
}
- aux += hnfo->ln_strlen;
- *matchlen = hnfo->match_len(ct, aux, limit, &shift);
+ *matchlen = hdr->match_len(ct, dptr, limit, &shift);
if (!*matchlen)
return -1;
-
- *matchoff = (aux - k) + shift;
-
- pr_debug("%s match succeeded! - len: %u\n", hnfo->lname,
- *matchlen);
+ *matchoff = dptr - start + shift;
return 1;
}
- pr_debug("%s header not found.\n", hnfo->lname);
return 0;
}
-EXPORT_SYMBOL_GPL(ct_sip_get_info);
+EXPORT_SYMBOL_GPL(ct_sip_get_header);
/* SDP header parsing: a SDP session description contains an ordered set of
* headers, starting with a section containing general session parameters,
^ permalink raw reply related [flat|nested] 39+ messages in thread* [NETFILTER 16/32]: nf_conntrack_sip: introduce SIP-URI parsing helper
2008-03-25 14:14 [METFILTER 00/32]: SIP helper update Patrick McHardy
` (14 preceding siblings ...)
2008-03-25 14:15 ` [NETFILTER 15/32]: nf_conntrack_sip: parse SIP headers properly Patrick McHardy
@ 2008-03-25 14:15 ` Patrick McHardy
2008-03-25 14:15 ` [NETFILTER 17/32]: nf_nat_sip: get rid of text based header translation Patrick McHardy
` (16 subsequent siblings)
32 siblings, 0 replies; 39+ messages in thread
From: Patrick McHardy @ 2008-03-25 14:15 UTC (permalink / raw)
To: davem; +Cc: Patrick McHardy, netfilter-devel
[NETFILTER]: nf_conntrack_sip: introduce SIP-URI parsing helper
Introduce a helper function to parse a SIP-URI in a header value, optionally
iterating through all headers of this kind.
Signed-off-by: Patrick McHardy <kaber@trash.net>
---
commit de9ecf6505dca564ede9b602715f8686e855f7bb
tree 86f40bda2cb52f719f51ffed5832f8ad629e42a1
parent 0b864cf59cb6bfb74677aa9c631b7c8df53016a2
author Patrick McHardy <kaber@trash.net> Tue, 25 Mar 2008 12:45:02 +0100
committer Patrick McHardy <kaber@trash.net> Tue, 25 Mar 2008 14:09:55 +0100
include/linux/netfilter/nf_conntrack_sip.h | 5 +
net/netfilter/nf_conntrack_sip.c | 107 ++++++++++++++++++++++++++++
2 files changed, 112 insertions(+), 0 deletions(-)
diff --git a/include/linux/netfilter/nf_conntrack_sip.h b/include/linux/netfilter/nf_conntrack_sip.h
index ccc7014..87bc6f7 100644
--- a/include/linux/netfilter/nf_conntrack_sip.h
+++ b/include/linux/netfilter/nf_conntrack_sip.h
@@ -67,6 +67,11 @@ extern int ct_sip_get_header(const struct nf_conn *ct, const char *dptr,
unsigned int dataoff, unsigned int datalen,
enum sip_header_types type,
unsigned int *matchoff, unsigned int *matchlen);
+extern int ct_sip_parse_header_uri(const struct nf_conn *ct, const char *dptr,
+ unsigned int *dataoff, unsigned int datalen,
+ enum sip_header_types type, int *in_header,
+ unsigned int *matchoff, unsigned int *matchlen,
+ union nf_inet_addr *addr, __be16 *port);
extern int ct_sip_get_sdp_header(const struct nf_conn *ct, const char *dptr,
unsigned int dataoff, unsigned int datalen,
diff --git a/net/netfilter/nf_conntrack_sip.c b/net/netfilter/nf_conntrack_sip.c
index cbc9159..a74d76a 100644
--- a/net/netfilter/nf_conntrack_sip.c
+++ b/net/netfilter/nf_conntrack_sip.c
@@ -190,6 +190,9 @@ EXPORT_SYMBOL_GPL(ct_sip_parse_request);
* whitespace and the values. Whitespace in this context means any amount of
* tabs, spaces and continuation lines, which are treated as a single whitespace
* character.
+ *
+ * Some headers may appear multiple times. A comma seperated list of values is
+ * equivalent to multiple headers.
*/
static const struct sip_header ct_sip_hdrs[] = {
[SIP_HDR_FROM] = SIP_HDR("From", "f", "sip:", skp_epaddr_len),
@@ -322,6 +325,110 @@ int ct_sip_get_header(const struct nf_conn *ct, const char *dptr,
}
EXPORT_SYMBOL_GPL(ct_sip_get_header);
+/* Get next header field in a list of comma seperated values */
+static int ct_sip_next_header(const struct nf_conn *ct, const char *dptr,
+ unsigned int dataoff, unsigned int datalen,
+ enum sip_header_types type,
+ unsigned int *matchoff, unsigned int *matchlen)
+{
+ const struct sip_header *hdr = &ct_sip_hdrs[type];
+ const char *start = dptr, *limit = dptr + datalen;
+ int shift = 0;
+
+ dptr += dataoff;
+
+ dptr = ct_sip_header_search(dptr, limit, ",", strlen(","));
+ if (!dptr)
+ return 0;
+
+ dptr = ct_sip_header_search(dptr, limit, hdr->search, hdr->slen);
+ if (!dptr)
+ return 0;
+ dptr += hdr->slen;
+
+ *matchoff = dptr - start;
+ *matchlen = hdr->match_len(ct, dptr, limit, &shift);
+ if (!*matchlen)
+ return -1;
+ *matchoff += shift;
+ return 1;
+}
+
+/* Walk through headers until a parsable one is found or no header of the
+ * given type is left. */
+static int ct_sip_walk_headers(const struct nf_conn *ct, const char *dptr,
+ unsigned int dataoff, unsigned int datalen,
+ enum sip_header_types type, int *in_header,
+ unsigned int *matchoff, unsigned int *matchlen)
+{
+ int ret;
+
+ if (in_header && *in_header) {
+ while (1) {
+ ret = ct_sip_next_header(ct, dptr, dataoff, datalen,
+ type, matchoff, matchlen);
+ if (ret > 0)
+ return ret;
+ if (ret == 0)
+ break;
+ dataoff += *matchoff;
+ }
+ *in_header = 0;
+ }
+
+ while (1) {
+ ret = ct_sip_get_header(ct, dptr, dataoff, datalen,
+ type, matchoff, matchlen);
+ if (ret > 0)
+ break;
+ if (ret == 0)
+ return ret;
+ dataoff += *matchoff;
+ }
+
+ if (in_header)
+ *in_header = 1;
+ return 1;
+}
+
+/* Locate a SIP header, parse the URI and return the offset and length of
+ * the address as well as the address and port themselves. A stream of
+ * headers can be parsed by handing in a non-NULL datalen and in_header
+ * pointer.
+ */
+int ct_sip_parse_header_uri(const struct nf_conn *ct, const char *dptr,
+ unsigned int *dataoff, unsigned int datalen,
+ enum sip_header_types type, int *in_header,
+ unsigned int *matchoff, unsigned int *matchlen,
+ union nf_inet_addr *addr, __be16 *port)
+{
+ const char *c, *limit = dptr + datalen;
+ unsigned int p;
+ int ret;
+
+ ret = ct_sip_walk_headers(ct, dptr, dataoff ? *dataoff : 0, datalen,
+ type, in_header, matchoff, matchlen);
+ WARN_ON(ret < 0);
+ if (ret == 0)
+ return ret;
+
+ if (!parse_addr(ct, dptr + *matchoff, &c, addr, limit))
+ return -1;
+ if (*c == ':') {
+ c++;
+ p = simple_strtoul(c, (char **)&c, 10);
+ if (p < 1024 || p > 65535)
+ return -1;
+ *port = htons(p);
+ } else
+ *port = htons(SIP_PORT);
+
+ if (dataoff)
+ *dataoff = c - dptr;
+ return 1;
+}
+EXPORT_SYMBOL_GPL(ct_sip_parse_header_uri);
+
/* SDP header parsing: a SDP session description contains an ordered set of
* headers, starting with a section containing general session parameters,
* optionally followed by multiple media descriptions.
^ permalink raw reply related [flat|nested] 39+ messages in thread* [NETFILTER 17/32]: nf_nat_sip: get rid of text based header translation
2008-03-25 14:14 [METFILTER 00/32]: SIP helper update Patrick McHardy
` (15 preceding siblings ...)
2008-03-25 14:15 ` [NETFILTER 16/32]: nf_conntrack_sip: introduce SIP-URI parsing helper Patrick McHardy
@ 2008-03-25 14:15 ` Patrick McHardy
2008-03-25 14:15 ` [NETFILTER 18/32]: nf_conntrack_sip: move SDP parsing to seperate function Patrick McHardy
` (15 subsequent siblings)
32 siblings, 0 replies; 39+ messages in thread
From: Patrick McHardy @ 2008-03-25 14:15 UTC (permalink / raw)
To: davem; +Cc: Patrick McHardy, netfilter-devel
[NETFILTER]: nf_nat_sip: get rid of text based header translation
Use the URI parsing helper to get the numerical addresses and get rid of the
text based header translation.
Signed-off-by: Patrick McHardy <kaber@trash.net>
---
commit fc9fe43590fd51627254f5c2aab859f23976b383
tree 1948e8fc9655147f474ffbd29f0c386c08376f11
parent de9ecf6505dca564ede9b602715f8686e855f7bb
author Patrick McHardy <kaber@trash.net> Tue, 25 Mar 2008 12:45:03 +0100
committer Patrick McHardy <kaber@trash.net> Tue, 25 Mar 2008 14:09:55 +0100
include/linux/netfilter/nf_conntrack_sip.h | 3 +
net/ipv4/netfilter/nf_nat_sip.c | 100 +++++++++++-----------------
net/netfilter/nf_conntrack_sip.c | 27 ++++++--
3 files changed, 62 insertions(+), 68 deletions(-)
diff --git a/include/linux/netfilter/nf_conntrack_sip.h b/include/linux/netfilter/nf_conntrack_sip.h
index 87bc6f7..68a0d6a 100644
--- a/include/linux/netfilter/nf_conntrack_sip.h
+++ b/include/linux/netfilter/nf_conntrack_sip.h
@@ -62,7 +62,8 @@ extern unsigned int (*nf_nat_sdp_hook)(struct sk_buff *skb,
extern int ct_sip_parse_request(const struct nf_conn *ct,
const char *dptr, unsigned int datalen,
- unsigned int *matchoff, unsigned int *matchlen);
+ unsigned int *matchoff, unsigned int *matchlen,
+ union nf_inet_addr *addr, __be16 *port);
extern int ct_sip_get_header(const struct nf_conn *ct, const char *dptr,
unsigned int dataoff, unsigned int datalen,
enum sip_header_types type,
diff --git a/net/ipv4/netfilter/nf_nat_sip.c b/net/ipv4/netfilter/nf_nat_sip.c
index c13e438..5b4a5cd 100644
--- a/net/ipv4/netfilter/nf_nat_sip.c
+++ b/net/ipv4/netfilter/nf_nat_sip.c
@@ -26,39 +26,6 @@ MODULE_AUTHOR("Christian Hentschel <chentschel@arnet.com.ar>");
MODULE_DESCRIPTION("SIP NAT helper");
MODULE_ALIAS("ip_nat_sip");
-struct addr_map {
- struct {
- char src[sizeof("nnn.nnn.nnn.nnn:nnnnn")];
- char dst[sizeof("nnn.nnn.nnn.nnn:nnnnn")];
- unsigned int srclen, srciplen;
- unsigned int dstlen, dstiplen;
- } addr[IP_CT_DIR_MAX];
-};
-
-static void addr_map_init(const struct nf_conn *ct, struct addr_map *map)
-{
- const struct nf_conntrack_tuple *t;
- enum ip_conntrack_dir dir;
- unsigned int n;
-
- for (dir = 0; dir < IP_CT_DIR_MAX; dir++) {
- t = &ct->tuplehash[dir].tuple;
-
- n = sprintf(map->addr[dir].src, "%u.%u.%u.%u",
- NIPQUAD(t->src.u3.ip));
- map->addr[dir].srciplen = n;
- n += sprintf(map->addr[dir].src + n, ":%u",
- ntohs(t->src.u.udp.port));
- map->addr[dir].srclen = n;
-
- n = sprintf(map->addr[dir].dst, "%u.%u.%u.%u",
- NIPQUAD(t->dst.u3.ip));
- map->addr[dir].dstiplen = n;
- n += sprintf(map->addr[dir].dst + n, ":%u",
- ntohs(t->dst.u.udp.port));
- map->addr[dir].dstlen = n;
- }
-}
static unsigned int mangle_packet(struct sk_buff *skb,
const char **dptr, unsigned int *datalen,
@@ -81,43 +48,51 @@ static unsigned int mangle_packet(struct sk_buff *skb,
static int map_addr(struct sk_buff *skb,
const char **dptr, unsigned int *datalen,
unsigned int matchoff, unsigned int matchlen,
- struct addr_map *map)
+ union nf_inet_addr *addr, __be16 port)
{
enum ip_conntrack_info ctinfo;
- struct nf_conn *ct __maybe_unused = nf_ct_get(skb, &ctinfo);
+ struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
- unsigned int addrlen;
- char *addr;
-
- if ((matchlen == map->addr[dir].srciplen ||
- matchlen == map->addr[dir].srclen) &&
- strncmp(*dptr + matchoff, map->addr[dir].src, matchlen) == 0) {
- addr = map->addr[!dir].dst;
- addrlen = map->addr[!dir].dstlen;
- } else if ((matchlen == map->addr[dir].dstiplen ||
- matchlen == map->addr[dir].dstlen) &&
- strncmp(*dptr + matchoff, map->addr[dir].dst, matchlen) == 0) {
- addr = map->addr[!dir].src;
- addrlen = map->addr[!dir].srclen;
+ char buffer[sizeof("nnn.nnn.nnn.nnn:nnnnn")];
+ unsigned int buflen;
+ __be32 newaddr;
+ __be16 newport;
+
+ if (ct->tuplehash[dir].tuple.src.u3.ip == addr->ip &&
+ ct->tuplehash[dir].tuple.src.u.udp.port == port) {
+ newaddr = ct->tuplehash[!dir].tuple.dst.u3.ip;
+ newport = ct->tuplehash[!dir].tuple.dst.u.udp.port;
+ } else if (ct->tuplehash[dir].tuple.dst.u3.ip == addr->ip &&
+ ct->tuplehash[dir].tuple.dst.u.udp.port == port) {
+ newaddr = ct->tuplehash[!dir].tuple.src.u3.ip;
+ newport = ct->tuplehash[!dir].tuple.src.u.udp.port;
} else
return 1;
+ if (newaddr == addr->ip && newport == port)
+ return 1;
+
+ buflen = sprintf(buffer, "%u.%u.%u.%u:%u",
+ NIPQUAD(newaddr), ntohs(newport));
+
return mangle_packet(skb, dptr, datalen, matchoff, matchlen,
- addr, addrlen);
+ buffer, buflen);
}
static int map_sip_addr(struct sk_buff *skb,
const char **dptr, unsigned int *datalen,
- enum sip_header_types type, struct addr_map *map)
+ enum sip_header_types type)
{
enum ip_conntrack_info ctinfo;
struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
unsigned int matchlen, matchoff;
+ union nf_inet_addr addr;
+ __be16 port;
- if (ct_sip_get_header(ct, *dptr, 0, *datalen, type,
- &matchoff, &matchlen) <= 0)
+ if (ct_sip_parse_header_uri(ct, *dptr, NULL, *datalen, type, NULL,
+ &matchoff, &matchlen, &addr, &port) <= 0)
return 1;
- return map_addr(skb, dptr, datalen, matchoff, matchlen, map);
+ return map_addr(skb, dptr, datalen, matchoff, matchlen, &addr, port);
}
static unsigned int ip_nat_sip(struct sk_buff *skb,
@@ -125,26 +100,27 @@ static unsigned int ip_nat_sip(struct sk_buff *skb,
{
enum ip_conntrack_info ctinfo;
struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
- struct addr_map map;
unsigned int matchoff, matchlen;
+ union nf_inet_addr addr;
+ __be16 port;
if (*datalen < strlen("SIP/2.0"))
return NF_ACCEPT;
- addr_map_init(ct, &map);
-
/* Basic rules: requests and responses. */
if (strnicmp(*dptr, "SIP/2.0", strlen("SIP/2.0")) != 0) {
if (ct_sip_parse_request(ct, *dptr, *datalen,
- &matchoff, &matchlen) > 0 &&
- !map_addr(skb, dptr, datalen, matchoff, matchlen, &map))
+ &matchoff, &matchlen,
+ &addr, &port) > 0 &&
+ !map_addr(skb, dptr, datalen, matchoff, matchlen,
+ &addr, port))
return NF_DROP;
}
- if (!map_sip_addr(skb, dptr, datalen, SIP_HDR_FROM, &map) ||
- !map_sip_addr(skb, dptr, datalen, SIP_HDR_TO, &map) ||
- !map_sip_addr(skb, dptr, datalen, SIP_HDR_VIA, &map) ||
- !map_sip_addr(skb, dptr, datalen, SIP_HDR_CONTACT, &map))
+ if (!map_sip_addr(skb, dptr, datalen, SIP_HDR_FROM) ||
+ !map_sip_addr(skb, dptr, datalen, SIP_HDR_TO) ||
+ !map_sip_addr(skb, dptr, datalen, SIP_HDR_VIA) ||
+ !map_sip_addr(skb, dptr, datalen, SIP_HDR_CONTACT))
return NF_DROP;
return NF_ACCEPT;
}
diff --git a/net/netfilter/nf_conntrack_sip.c b/net/netfilter/nf_conntrack_sip.c
index a74d76a..f20fa2d 100644
--- a/net/netfilter/nf_conntrack_sip.c
+++ b/net/netfilter/nf_conntrack_sip.c
@@ -151,10 +151,12 @@ static int skp_epaddr_len(const struct nf_conn *ct, const char *dptr,
*/
int ct_sip_parse_request(const struct nf_conn *ct,
const char *dptr, unsigned int datalen,
- unsigned int *matchoff, unsigned int *matchlen)
+ unsigned int *matchoff, unsigned int *matchlen,
+ union nf_inet_addr *addr, __be16 *port)
{
- const char *start = dptr, *limit = dptr + datalen;
+ const char *start = dptr, *limit = dptr + datalen, *end;
unsigned int mlen;
+ unsigned int p;
int shift = 0;
/* Skip method and following whitespace */
@@ -173,10 +175,25 @@ int ct_sip_parse_request(const struct nf_conn *ct,
if (strnicmp(dptr, "sip:", strlen("sip:")) == 0)
break;
}
- *matchlen = skp_epaddr_len(ct, dptr, limit, &shift);
- if (!*matchlen)
+ if (!skp_epaddr_len(ct, dptr, limit, &shift))
return 0;
- *matchoff = dptr - start + shift;
+ dptr += shift;
+
+ if (!parse_addr(ct, dptr, &end, addr, limit))
+ return -1;
+ if (end < limit && *end == ':') {
+ end++;
+ p = simple_strtoul(end, (char **)&end, 10);
+ if (p < 1024 || p > 65535)
+ return -1;
+ *port = htons(p);
+ } else
+ *port = htons(SIP_PORT);
+
+ if (end == dptr)
+ return 0;
+ *matchoff = dptr - start;
+ *matchlen = end - dptr;
return 1;
}
EXPORT_SYMBOL_GPL(ct_sip_parse_request);
^ permalink raw reply related [flat|nested] 39+ messages in thread* [NETFILTER 18/32]: nf_conntrack_sip: move SDP parsing to seperate function
2008-03-25 14:14 [METFILTER 00/32]: SIP helper update Patrick McHardy
` (16 preceding siblings ...)
2008-03-25 14:15 ` [NETFILTER 17/32]: nf_nat_sip: get rid of text based header translation Patrick McHardy
@ 2008-03-25 14:15 ` Patrick McHardy
2008-03-25 14:15 ` [NETFILTER 19/32]: nf_conntrack_sip: support method specific request/response handling Patrick McHardy
` (14 subsequent siblings)
32 siblings, 0 replies; 39+ messages in thread
From: Patrick McHardy @ 2008-03-25 14:15 UTC (permalink / raw)
To: davem; +Cc: Patrick McHardy, netfilter-devel
[NETFILTER]: nf_conntrack_sip: move SDP parsing to seperate function
Signed-off-by: Patrick McHardy <kaber@trash.net>
---
commit 19639f6bcaed278e3fbc60d69f573e5c117bc4f2
tree aa2dfd07bf03862400f034b44af3874449b92d52
parent fc9fe43590fd51627254f5c2aab859f23976b383
author Patrick McHardy <kaber@trash.net> Tue, 25 Mar 2008 12:45:05 +0100
committer Patrick McHardy <kaber@trash.net> Tue, 25 Mar 2008 14:09:56 +0100
net/netfilter/nf_conntrack_sip.c | 84 +++++++++++++++++++-------------------
1 files changed, 43 insertions(+), 41 deletions(-)
diff --git a/net/netfilter/nf_conntrack_sip.c b/net/netfilter/nf_conntrack_sip.c
index f20fa2d..96bedb5 100644
--- a/net/netfilter/nf_conntrack_sip.c
+++ b/net/netfilter/nf_conntrack_sip.c
@@ -565,19 +565,49 @@ static int set_expected_rtp(struct sk_buff *skb,
return ret;
}
+static int process_sdp(struct sk_buff *skb,
+ const char **dptr, unsigned int *datalen)
+{
+ enum ip_conntrack_info ctinfo;
+ struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
+ int family = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.l3num;
+ unsigned int matchoff, matchlen;
+ union nf_inet_addr addr;
+ unsigned int port;
+ enum sdp_header_types type;
+
+ /* Get address and port from SDP packet. */
+ type = family == AF_INET ? SDP_HDR_CONNECTION_IP4 :
+ SDP_HDR_CONNECTION_IP6;
+
+ if (ct_sip_get_sdp_header(ct, *dptr, 0, *datalen,
+ type, SDP_HDR_UNSPEC,
+ &matchoff, &matchlen) <= 0)
+ return NF_ACCEPT;
+
+ /* We'll drop only if there are parse problems. */
+ if (!parse_addr(ct, *dptr + matchoff, NULL, &addr, *dptr + *datalen))
+ return NF_DROP;
+
+ if (ct_sip_get_sdp_header(ct, *dptr, 0, *datalen,
+ SDP_HDR_MEDIA, SDP_HDR_UNSPEC,
+ &matchoff, &matchlen) <= 0)
+ return NF_ACCEPT;
+
+ port = simple_strtoul(*dptr + matchoff, NULL, 10);
+ if (port < 1024 || port > 65535)
+ return NF_DROP;
+
+ return set_expected_rtp(skb, dptr, datalen, &addr, htons(port));
+}
+
static int sip_help(struct sk_buff *skb,
unsigned int protoff,
struct nf_conn *ct,
enum ip_conntrack_info ctinfo)
{
- int family = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.l3num;
- union nf_inet_addr addr;
unsigned int dataoff, datalen;
const char *dptr;
- int ret = NF_ACCEPT;
- unsigned int matchoff, matchlen;
- u_int16_t port;
- enum sdp_header_types type;
typeof(nf_nat_sip_hook) nf_nat_sip;
/* No Data ? */
@@ -591,56 +621,28 @@ static int sip_help(struct sk_buff *skb,
dptr = skb->data + dataoff;
else {
pr_debug("Copy of skbuff not supported yet.\n");
- goto out;
+ return NF_ACCEPT;
}
nf_nat_sip = rcu_dereference(nf_nat_sip_hook);
if (nf_nat_sip && ct->status & IPS_NAT_MASK) {
- if (!nf_nat_sip(skb, &dptr, &datalen)) {
- ret = NF_DROP;
- goto out;
- }
+ if (!nf_nat_sip(skb, &dptr, &datalen))
+ return NF_DROP;
}
datalen = skb->len - dataoff;
if (datalen < strlen("SIP/2.0 200"))
- goto out;
+ return NF_ACCEPT;
/* RTP info only in some SDP pkts */
if (strnicmp(dptr, "INVITE", strlen("INVITE")) != 0 &&
strnicmp(dptr, "UPDATE", strlen("UPDATE")) != 0 &&
strnicmp(dptr, "SIP/2.0 180", strlen("SIP/2.0 180")) != 0 &&
strnicmp(dptr, "SIP/2.0 183", strlen("SIP/2.0 183")) != 0 &&
- strnicmp(dptr, "SIP/2.0 200", strlen("SIP/2.0 200")) != 0) {
- goto out;
- }
- /* Get address and port from SDP packet. */
- type = family == AF_INET ? SDP_HDR_CONNECTION_IP4 :
- SDP_HDR_CONNECTION_IP6;
- if (ct_sip_get_sdp_header(ct, dptr, 0, datalen, type, SDP_HDR_UNSPEC,
- &matchoff, &matchlen) > 0) {
+ strnicmp(dptr, "SIP/2.0 200", strlen("SIP/2.0 200")) != 0)
+ return NF_ACCEPT;
- /* We'll drop only if there are parse problems. */
- if (!parse_addr(ct, dptr + matchoff, NULL, &addr,
- dptr + datalen)) {
- ret = NF_DROP;
- goto out;
- }
- if (ct_sip_get_sdp_header(ct, dptr, 0, datalen,
- SDP_HDR_MEDIA, SDP_HDR_UNSPEC,
- &matchoff, &matchlen) > 0) {
-
- port = simple_strtoul(dptr + matchoff, NULL, 10);
- if (port < 1024) {
- ret = NF_DROP;
- goto out;
- }
- ret = set_expected_rtp(skb, &dptr, &datalen,
- &addr, htons(port));
- }
- }
-out:
- return ret;
+ return process_sdp(skb, &dptr, &datalen);
}
static struct nf_conntrack_helper sip[MAX_PORTS][2] __read_mostly;
^ permalink raw reply related [flat|nested] 39+ messages in thread* [NETFILTER 19/32]: nf_conntrack_sip: support method specific request/response handling
2008-03-25 14:14 [METFILTER 00/32]: SIP helper update Patrick McHardy
` (17 preceding siblings ...)
2008-03-25 14:15 ` [NETFILTER 18/32]: nf_conntrack_sip: move SDP parsing to seperate function Patrick McHardy
@ 2008-03-25 14:15 ` Patrick McHardy
2008-03-25 14:15 ` [NETFILTER 20/32]: nf_conntrack_sip: perform NAT after parsing Patrick McHardy
` (13 subsequent siblings)
32 siblings, 0 replies; 39+ messages in thread
From: Patrick McHardy @ 2008-03-25 14:15 UTC (permalink / raw)
To: davem; +Cc: Patrick McHardy, netfilter-devel
[NETFILTER]: nf_conntrack_sip: support method specific request/response handling
Add support for per-method request/response handlers and perform SDP
parsing for INVITE/UPDATE requests and for all informational and
successful responses.
Signed-off-by: Patrick McHardy <kaber@trash.net>
---
commit 607087bf4071e8b15660d0ef2dbed696697a4516
tree cdebc3c60b5346536a993586c2004d7215d4f5ed
parent 19639f6bcaed278e3fbc60d69f573e5c117bc4f2
author Patrick McHardy <kaber@trash.net> Tue, 25 Mar 2008 12:45:06 +0100
committer Patrick McHardy <kaber@trash.net> Tue, 25 Mar 2008 14:09:56 +0100
include/linux/netfilter/nf_conntrack_sip.h | 20 +++++
net/netfilter/nf_conntrack_sip.c | 107 +++++++++++++++++++++++++---
2 files changed, 117 insertions(+), 10 deletions(-)
diff --git a/include/linux/netfilter/nf_conntrack_sip.h b/include/linux/netfilter/nf_conntrack_sip.h
index 68a0d6a..da93e80 100644
--- a/include/linux/netfilter/nf_conntrack_sip.h
+++ b/include/linux/netfilter/nf_conntrack_sip.h
@@ -5,6 +5,25 @@
#define SIP_PORT 5060
#define SIP_TIMEOUT 3600
+struct sip_handler {
+ const char *method;
+ unsigned int len;
+ int (*request)(struct sk_buff *skb,
+ const char **dptr, unsigned int *datalen,
+ unsigned int cseq);
+ int (*response)(struct sk_buff *skb,
+ const char **dptr, unsigned int *datalen,
+ unsigned int cseq, unsigned int code);
+};
+
+#define SIP_HANDLER(__method, __request, __response) \
+{ \
+ .method = (__method), \
+ .len = sizeof(__method) - 1, \
+ .request = (__request), \
+ .response = (__response), \
+}
+
struct sip_header {
const char *name;
const char *cname;
@@ -35,6 +54,7 @@ struct sip_header {
__SIP_HDR(__name, NULL, __search, __match)
enum sip_header_types {
+ SIP_HDR_CSEQ,
SIP_HDR_FROM,
SIP_HDR_TO,
SIP_HDR_CONTACT,
diff --git a/net/netfilter/nf_conntrack_sip.c b/net/netfilter/nf_conntrack_sip.c
index 96bedb5..1be949f 100644
--- a/net/netfilter/nf_conntrack_sip.c
+++ b/net/netfilter/nf_conntrack_sip.c
@@ -212,6 +212,7 @@ EXPORT_SYMBOL_GPL(ct_sip_parse_request);
* equivalent to multiple headers.
*/
static const struct sip_header ct_sip_hdrs[] = {
+ [SIP_HDR_CSEQ] = SIP_HDR("CSeq", NULL, NULL, digits_len),
[SIP_HDR_FROM] = SIP_HDR("From", "f", "sip:", skp_epaddr_len),
[SIP_HDR_TO] = SIP_HDR("To", "t", "sip:", skp_epaddr_len),
[SIP_HDR_CONTACT] = SIP_HDR("Contact", "m", "sip:", skp_epaddr_len),
@@ -566,7 +567,8 @@ static int set_expected_rtp(struct sk_buff *skb,
}
static int process_sdp(struct sk_buff *skb,
- const char **dptr, unsigned int *datalen)
+ const char **dptr, unsigned int *datalen,
+ unsigned int cseq)
{
enum ip_conntrack_info ctinfo;
struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
@@ -600,6 +602,96 @@ static int process_sdp(struct sk_buff *skb,
return set_expected_rtp(skb, dptr, datalen, &addr, htons(port));
}
+static int process_invite_response(struct sk_buff *skb,
+ const char **dptr, unsigned int *datalen,
+ unsigned int cseq, unsigned int code)
+{
+ if ((code >= 100 && code <= 199) ||
+ (code >= 200 && code <= 299))
+ return process_sdp(skb, dptr, datalen, cseq);
+
+ return NF_ACCEPT;
+}
+
+static int process_update_response(struct sk_buff *skb,
+ const char **dptr, unsigned int *datalen,
+ unsigned int cseq, unsigned int code)
+{
+ if ((code >= 100 && code <= 199) ||
+ (code >= 200 && code <= 299))
+ return process_sdp(skb, dptr, datalen, cseq);
+
+ return NF_ACCEPT;
+}
+
+static const struct sip_handler sip_handlers[] = {
+ SIP_HANDLER("INVITE", process_sdp, process_invite_response),
+ SIP_HANDLER("UPDATE", process_sdp, process_update_response),
+};
+
+static int process_sip_response(struct sk_buff *skb,
+ const char **dptr, unsigned int *datalen)
+{
+ static const struct sip_handler *handler;
+ enum ip_conntrack_info ctinfo;
+ struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
+ unsigned int matchoff, matchlen;
+ unsigned int code, cseq, dataoff, i;
+
+ if (*datalen < strlen("SIP/2.0 200"))
+ return NF_ACCEPT;
+ code = simple_strtoul(*dptr + strlen("SIP/2.0 "), NULL, 10);
+ if (!code)
+ return NF_DROP;
+
+ if (ct_sip_get_header(ct, *dptr, 0, *datalen, SIP_HDR_CSEQ,
+ &matchoff, &matchlen) <= 0)
+ return NF_DROP;
+ cseq = simple_strtoul(*dptr + matchoff, NULL, 10);
+ if (!cseq)
+ return NF_DROP;
+ dataoff = matchoff + matchlen + 1;
+
+ for (i = 0; i < ARRAY_SIZE(sip_handlers); i++) {
+ handler = &sip_handlers[i];
+ if (handler->response == NULL)
+ continue;
+ if (*datalen < dataoff + handler->len ||
+ strnicmp(*dptr + dataoff, handler->method, handler->len))
+ continue;
+ return handler->response(skb, dptr, datalen, cseq, code);
+ }
+ return NF_ACCEPT;
+}
+
+static int process_sip_request(struct sk_buff *skb,
+ const char **dptr, unsigned int *datalen)
+{
+ static const struct sip_handler *handler;
+ enum ip_conntrack_info ctinfo;
+ struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
+ unsigned int matchoff, matchlen;
+ unsigned int cseq, i;
+
+ for (i = 0; i < ARRAY_SIZE(sip_handlers); i++) {
+ handler = &sip_handlers[i];
+ if (handler->request == NULL)
+ continue;
+ if (*datalen < handler->len ||
+ strnicmp(*dptr, handler->method, handler->len))
+ continue;
+
+ if (ct_sip_get_header(ct, *dptr, 0, *datalen, SIP_HDR_CSEQ,
+ &matchoff, &matchlen) <= 0)
+ return NF_DROP;
+ cseq = simple_strtoul(*dptr + matchoff, NULL, 10);
+ if (!cseq)
+ return NF_DROP;
+
+ return handler->request(skb, dptr, datalen, cseq);
+ }
+ return NF_ACCEPT;
+}
static int sip_help(struct sk_buff *skb,
unsigned int protoff,
@@ -634,15 +726,10 @@ static int sip_help(struct sk_buff *skb,
if (datalen < strlen("SIP/2.0 200"))
return NF_ACCEPT;
- /* RTP info only in some SDP pkts */
- if (strnicmp(dptr, "INVITE", strlen("INVITE")) != 0 &&
- strnicmp(dptr, "UPDATE", strlen("UPDATE")) != 0 &&
- strnicmp(dptr, "SIP/2.0 180", strlen("SIP/2.0 180")) != 0 &&
- strnicmp(dptr, "SIP/2.0 183", strlen("SIP/2.0 183")) != 0 &&
- strnicmp(dptr, "SIP/2.0 200", strlen("SIP/2.0 200")) != 0)
- return NF_ACCEPT;
-
- return process_sdp(skb, &dptr, &datalen);
+ if (strnicmp(dptr, "SIP/2.0 ", strlen("SIP/2.0 ")) != 0)
+ return process_sip_request(skb, &dptr, &datalen);
+ else
+ return process_sip_response(skb, &dptr, &datalen);
}
static struct nf_conntrack_helper sip[MAX_PORTS][2] __read_mostly;
^ permalink raw reply related [flat|nested] 39+ messages in thread* [NETFILTER 20/32]: nf_conntrack_sip: perform NAT after parsing
2008-03-25 14:14 [METFILTER 00/32]: SIP helper update Patrick McHardy
` (18 preceding siblings ...)
2008-03-25 14:15 ` [NETFILTER 19/32]: nf_conntrack_sip: support method specific request/response handling Patrick McHardy
@ 2008-03-25 14:15 ` Patrick McHardy
2008-03-25 14:15 ` [NETFILTER 21/32]: nf_conntrack_sip: process ACK and PRACK methods Patrick McHardy
` (12 subsequent siblings)
32 siblings, 0 replies; 39+ messages in thread
From: Patrick McHardy @ 2008-03-25 14:15 UTC (permalink / raw)
To: davem; +Cc: Patrick McHardy, netfilter-devel
[NETFILTER]: nf_conntrack_sip: perform NAT after parsing
Perform NAT last after parsing the packet. This makes no difference
currently, but is needed when dealing with registrations to make
sure we seen the unNATed addresses.
Signed-off-by: Patrick McHardy <kaber@trash.net>
---
commit bbec485758c30e4c7bc04dbc387ed9cea676bc24
tree bb37b6940482c64c306f55c1aec3fd8103e7c5a4
parent 607087bf4071e8b15660d0ef2dbed696697a4516
author Patrick McHardy <kaber@trash.net> Tue, 25 Mar 2008 12:45:08 +0100
committer Patrick McHardy <kaber@trash.net> Tue, 25 Mar 2008 14:09:56 +0100
net/ipv4/netfilter/nf_nat_sip.c | 3 ---
net/netfilter/nf_conntrack_sip.c | 19 +++++++++++--------
2 files changed, 11 insertions(+), 11 deletions(-)
diff --git a/net/ipv4/netfilter/nf_nat_sip.c b/net/ipv4/netfilter/nf_nat_sip.c
index 5b4a5cd..b442810 100644
--- a/net/ipv4/netfilter/nf_nat_sip.c
+++ b/net/ipv4/netfilter/nf_nat_sip.c
@@ -104,9 +104,6 @@ static unsigned int ip_nat_sip(struct sk_buff *skb,
union nf_inet_addr addr;
__be16 port;
- if (*datalen < strlen("SIP/2.0"))
- return NF_ACCEPT;
-
/* Basic rules: requests and responses. */
if (strnicmp(*dptr, "SIP/2.0", strlen("SIP/2.0")) != 0) {
if (ct_sip_parse_request(ct, *dptr, *datalen,
diff --git a/net/netfilter/nf_conntrack_sip.c b/net/netfilter/nf_conntrack_sip.c
index 1be949f..29a37d2 100644
--- a/net/netfilter/nf_conntrack_sip.c
+++ b/net/netfilter/nf_conntrack_sip.c
@@ -700,6 +700,7 @@ static int sip_help(struct sk_buff *skb,
{
unsigned int dataoff, datalen;
const char *dptr;
+ int ret;
typeof(nf_nat_sip_hook) nf_nat_sip;
/* No Data ? */
@@ -716,20 +717,22 @@ static int sip_help(struct sk_buff *skb,
return NF_ACCEPT;
}
- nf_nat_sip = rcu_dereference(nf_nat_sip_hook);
- if (nf_nat_sip && ct->status & IPS_NAT_MASK) {
- if (!nf_nat_sip(skb, &dptr, &datalen))
- return NF_DROP;
- }
-
datalen = skb->len - dataoff;
if (datalen < strlen("SIP/2.0 200"))
return NF_ACCEPT;
if (strnicmp(dptr, "SIP/2.0 ", strlen("SIP/2.0 ")) != 0)
- return process_sip_request(skb, &dptr, &datalen);
+ ret = process_sip_request(skb, &dptr, &datalen);
else
- return process_sip_response(skb, &dptr, &datalen);
+ ret = process_sip_response(skb, &dptr, &datalen);
+
+ if (ret == NF_ACCEPT && ct->status & IPS_NAT_MASK) {
+ nf_nat_sip = rcu_dereference(nf_nat_sip_hook);
+ if (nf_nat_sip && !nf_nat_sip(skb, &dptr, &datalen))
+ ret = NF_DROP;
+ }
+
+ return ret;
}
static struct nf_conntrack_helper sip[MAX_PORTS][2] __read_mostly;
^ permalink raw reply related [flat|nested] 39+ messages in thread* [NETFILTER 21/32]: nf_conntrack_sip: process ACK and PRACK methods
2008-03-25 14:14 [METFILTER 00/32]: SIP helper update Patrick McHardy
` (19 preceding siblings ...)
2008-03-25 14:15 ` [NETFILTER 20/32]: nf_conntrack_sip: perform NAT after parsing Patrick McHardy
@ 2008-03-25 14:15 ` Patrick McHardy
2008-03-25 14:15 ` [NETFILTER 22/32]: nf_conntrack_sip: flush expectations on call termination Patrick McHardy
` (11 subsequent siblings)
32 siblings, 0 replies; 39+ messages in thread
From: Patrick McHardy @ 2008-03-25 14:15 UTC (permalink / raw)
To: davem; +Cc: Patrick McHardy, netfilter-devel
[NETFILTER]: nf_conntrack_sip: process ACK and PRACK methods
Both may contains SDP offers/answers.
Signed-off-by: Patrick McHardy <kaber@trash.net>
---
commit fc1d4b6b9937a801590c454b68317734a809be0b
tree c4b167a12ff72abae20998cb0be31157306b4ba8
parent bbec485758c30e4c7bc04dbc387ed9cea676bc24
author Patrick McHardy <kaber@trash.net> Tue, 25 Mar 2008 12:45:09 +0100
committer Patrick McHardy <kaber@trash.net> Tue, 25 Mar 2008 14:09:56 +0100
net/netfilter/nf_conntrack_sip.c | 13 +++++++++++++
1 files changed, 13 insertions(+), 0 deletions(-)
diff --git a/net/netfilter/nf_conntrack_sip.c b/net/netfilter/nf_conntrack_sip.c
index 29a37d2..71f744a 100644
--- a/net/netfilter/nf_conntrack_sip.c
+++ b/net/netfilter/nf_conntrack_sip.c
@@ -624,9 +624,22 @@ static int process_update_response(struct sk_buff *skb,
return NF_ACCEPT;
}
+static int process_prack_response(struct sk_buff *skb,
+ const char **dptr, unsigned int *datalen,
+ unsigned int cseq, unsigned int code)
+{
+ if ((code >= 100 && code <= 199) ||
+ (code >= 200 && code <= 299))
+ return process_sdp(skb, dptr, datalen, cseq);
+
+ return NF_ACCEPT;
+}
+
static const struct sip_handler sip_handlers[] = {
SIP_HANDLER("INVITE", process_sdp, process_invite_response),
SIP_HANDLER("UPDATE", process_sdp, process_update_response),
+ SIP_HANDLER("ACK", process_sdp, NULL),
+ SIP_HANDLER("PRACK", process_sdp, process_prack_response),
};
static int process_sip_response(struct sk_buff *skb,
^ permalink raw reply related [flat|nested] 39+ messages in thread* [NETFILTER 22/32]: nf_conntrack_sip: flush expectations on call termination
2008-03-25 14:14 [METFILTER 00/32]: SIP helper update Patrick McHardy
` (20 preceding siblings ...)
2008-03-25 14:15 ` [NETFILTER 21/32]: nf_conntrack_sip: process ACK and PRACK methods Patrick McHardy
@ 2008-03-25 14:15 ` Patrick McHardy
2008-03-25 14:15 ` [NETFILTER 23/32]: nf_conntrack_sip: introduce URI and header parameter parsing helpers Patrick McHardy
` (10 subsequent siblings)
32 siblings, 0 replies; 39+ messages in thread
From: Patrick McHardy @ 2008-03-25 14:15 UTC (permalink / raw)
To: davem; +Cc: Patrick McHardy, netfilter-devel
[NETFILTER]: nf_conntrack_sip: flush expectations on call termination
Flush the RTP expectations we've created when a call is hung up or
terminated otherwise.
Signed-off-by: Patrick McHardy <kaber@trash.net>
---
commit 26599b7c1bd613fbb4f397ebfb64fd01a5f34068
tree 70f97fa632aa7a92787d0e8e527269099fb04769
parent fc1d4b6b9937a801590c454b68317734a809be0b
author Patrick McHardy <kaber@trash.net> Tue, 25 Mar 2008 12:45:11 +0100
committer Patrick McHardy <kaber@trash.net> Tue, 25 Mar 2008 14:09:57 +0100
net/netfilter/nf_conntrack_sip.c | 52 +++++++++++++++++++++++++++++++++++---
1 files changed, 48 insertions(+), 4 deletions(-)
diff --git a/net/netfilter/nf_conntrack_sip.c b/net/netfilter/nf_conntrack_sip.c
index 71f744a..8e7e5b4 100644
--- a/net/netfilter/nf_conntrack_sip.c
+++ b/net/netfilter/nf_conntrack_sip.c
@@ -17,6 +17,7 @@
#include <linux/netfilter.h>
#include <net/netfilter/nf_conntrack.h>
+#include <net/netfilter/nf_conntrack_core.h>
#include <net/netfilter/nf_conntrack_expect.h>
#include <net/netfilter/nf_conntrack_helper.h>
#include <linux/netfilter/nf_conntrack_sip.h>
@@ -533,6 +534,22 @@ int ct_sip_get_sdp_header(const struct nf_conn *ct, const char *dptr,
}
EXPORT_SYMBOL_GPL(ct_sip_get_sdp_header);
+static void flush_expectations(struct nf_conn *ct)
+{
+ struct nf_conn_help *help = nfct_help(ct);
+ struct nf_conntrack_expect *exp;
+ struct hlist_node *n, *next;
+
+ spin_lock_bh(&nf_conntrack_lock);
+ hlist_for_each_entry_safe(exp, n, next, &help->expectations, lnode) {
+ if (!del_timer(&exp->timeout))
+ continue;
+ nf_ct_unlink_expect(exp);
+ nf_ct_expect_put(exp);
+ }
+ spin_unlock_bh(&nf_conntrack_lock);
+}
+
static int set_expected_rtp(struct sk_buff *skb,
const char **dptr, unsigned int *datalen,
union nf_inet_addr *addr, __be16 port)
@@ -606,32 +623,58 @@ static int process_invite_response(struct sk_buff *skb,
const char **dptr, unsigned int *datalen,
unsigned int cseq, unsigned int code)
{
+ enum ip_conntrack_info ctinfo;
+ struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
+
if ((code >= 100 && code <= 199) ||
(code >= 200 && code <= 299))
return process_sdp(skb, dptr, datalen, cseq);
-
- return NF_ACCEPT;
+ else {
+ flush_expectations(ct);
+ return NF_ACCEPT;
+ }
}
static int process_update_response(struct sk_buff *skb,
const char **dptr, unsigned int *datalen,
unsigned int cseq, unsigned int code)
{
+ enum ip_conntrack_info ctinfo;
+ struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
+
if ((code >= 100 && code <= 199) ||
(code >= 200 && code <= 299))
return process_sdp(skb, dptr, datalen, cseq);
-
- return NF_ACCEPT;
+ else {
+ flush_expectations(ct);
+ return NF_ACCEPT;
+ }
}
static int process_prack_response(struct sk_buff *skb,
const char **dptr, unsigned int *datalen,
unsigned int cseq, unsigned int code)
{
+ enum ip_conntrack_info ctinfo;
+ struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
+
if ((code >= 100 && code <= 199) ||
(code >= 200 && code <= 299))
return process_sdp(skb, dptr, datalen, cseq);
+ else {
+ flush_expectations(ct);
+ return NF_ACCEPT;
+ }
+}
+
+static int process_bye_request(struct sk_buff *skb,
+ const char **dptr, unsigned int *datalen,
+ unsigned int cseq)
+{
+ enum ip_conntrack_info ctinfo;
+ struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
+ flush_expectations(ct);
return NF_ACCEPT;
}
@@ -640,6 +683,7 @@ static const struct sip_handler sip_handlers[] = {
SIP_HANDLER("UPDATE", process_sdp, process_update_response),
SIP_HANDLER("ACK", process_sdp, NULL),
SIP_HANDLER("PRACK", process_sdp, process_prack_response),
+ SIP_HANDLER("BYE", process_bye_request, NULL),
};
static int process_sip_response(struct sk_buff *skb,
^ permalink raw reply related [flat|nested] 39+ messages in thread* [NETFILTER 23/32]: nf_conntrack_sip: introduce URI and header parameter parsing helpers
2008-03-25 14:14 [METFILTER 00/32]: SIP helper update Patrick McHardy
` (21 preceding siblings ...)
2008-03-25 14:15 ` [NETFILTER 22/32]: nf_conntrack_sip: flush expectations on call termination Patrick McHardy
@ 2008-03-25 14:15 ` Patrick McHardy
2008-03-25 14:15 ` [NETFILTER 24/32]: nf_nat_sip: translate all Via headers Patrick McHardy
` (9 subsequent siblings)
32 siblings, 0 replies; 39+ messages in thread
From: Patrick McHardy @ 2008-03-25 14:15 UTC (permalink / raw)
To: davem; +Cc: Patrick McHardy, netfilter-devel
[NETFILTER]: nf_conntrack_sip: introduce URI and header parameter parsing helpers
Introduce URI and header parameter parsing helpers. These are needed
by the conntrack helper to parse expiration values in Contact: header
parameters and by the NAT helper to properly update the Via-header
rport=, received= and maddr= parameters.
Signed-off-by: Patrick McHardy <kaber@trash.net>
---
commit 2a21cab1320505abe9059adb8d42a130ea36e15b
tree 9dd17f5ddaf115146c65f6c3c2fddbcd88ac8b27
parent 26599b7c1bd613fbb4f397ebfb64fd01a5f34068
author Patrick McHardy <kaber@trash.net> Tue, 25 Mar 2008 12:45:13 +0100
committer Patrick McHardy <kaber@trash.net> Tue, 25 Mar 2008 14:09:57 +0100
include/linux/netfilter/nf_conntrack_sip.h | 10 +++++
net/netfilter/nf_conntrack_sip.c | 58 ++++++++++++++++++++++++++++
2 files changed, 68 insertions(+), 0 deletions(-)
diff --git a/include/linux/netfilter/nf_conntrack_sip.h b/include/linux/netfilter/nf_conntrack_sip.h
index da93e80..87e4028 100644
--- a/include/linux/netfilter/nf_conntrack_sip.h
+++ b/include/linux/netfilter/nf_conntrack_sip.h
@@ -93,6 +93,16 @@ extern int ct_sip_parse_header_uri(const struct nf_conn *ct, const char *dptr,
enum sip_header_types type, int *in_header,
unsigned int *matchoff, unsigned int *matchlen,
union nf_inet_addr *addr, __be16 *port);
+extern int ct_sip_parse_address_param(const struct nf_conn *ct, const char *dptr,
+ unsigned int dataoff, unsigned int datalen,
+ const char *name,
+ unsigned int *matchoff, unsigned int *matchlen,
+ union nf_inet_addr *addr);
+extern int ct_sip_parse_numerical_param(const struct nf_conn *ct, const char *dptr,
+ unsigned int off, unsigned int datalen,
+ const char *name,
+ unsigned int *matchoff, unsigned int *matchen,
+ unsigned int *val);
extern int ct_sip_get_sdp_header(const struct nf_conn *ct, const char *dptr,
unsigned int dataoff, unsigned int datalen,
diff --git a/net/netfilter/nf_conntrack_sip.c b/net/netfilter/nf_conntrack_sip.c
index 8e7e5b4..126f308 100644
--- a/net/netfilter/nf_conntrack_sip.c
+++ b/net/netfilter/nf_conntrack_sip.c
@@ -448,6 +448,64 @@ int ct_sip_parse_header_uri(const struct nf_conn *ct, const char *dptr,
}
EXPORT_SYMBOL_GPL(ct_sip_parse_header_uri);
+/* Parse address from header parameter and return address, offset and length */
+int ct_sip_parse_address_param(const struct nf_conn *ct, const char *dptr,
+ unsigned int dataoff, unsigned int datalen,
+ const char *name,
+ unsigned int *matchoff, unsigned int *matchlen,
+ union nf_inet_addr *addr)
+{
+ const char *limit = dptr + datalen;
+ const char *start, *end;
+
+ limit = ct_sip_header_search(dptr + dataoff, limit, ",", strlen(","));
+ if (!limit)
+ limit = dptr + datalen;
+
+ start = ct_sip_header_search(dptr + dataoff, limit, name, strlen(name));
+ if (!start)
+ return 0;
+
+ start += strlen(name);
+ if (!parse_addr(ct, start, &end, addr, limit))
+ return 0;
+ *matchoff = start - dptr;
+ *matchlen = end - start;
+ return 1;
+}
+EXPORT_SYMBOL_GPL(ct_sip_parse_address_param);
+
+/* Parse numerical header parameter and return value, offset and length */
+int ct_sip_parse_numerical_param(const struct nf_conn *ct, const char *dptr,
+ unsigned int dataoff, unsigned int datalen,
+ const char *name,
+ unsigned int *matchoff, unsigned int *matchlen,
+ unsigned int *val)
+{
+ const char *limit = dptr + datalen;
+ const char *start;
+ char *end;
+
+ limit = ct_sip_header_search(dptr + dataoff, limit, ",", strlen(","));
+ if (!limit)
+ limit = dptr + datalen;
+
+ start = ct_sip_header_search(dptr + dataoff, limit, name, strlen(name));
+ if (!start)
+ return 0;
+
+ start += strlen(name);
+ *val = simple_strtoul(start, &end, 0);
+ if (start == end)
+ return 0;
+ if (matchoff && matchlen) {
+ *matchoff = start - dptr;
+ *matchlen = end - start;
+ }
+ return 1;
+}
+EXPORT_SYMBOL_GPL(ct_sip_parse_numerical_param);
+
/* SDP header parsing: a SDP session description contains an ordered set of
* headers, starting with a section containing general session parameters,
* optionally followed by multiple media descriptions.
^ permalink raw reply related [flat|nested] 39+ messages in thread* [NETFILTER 24/32]: nf_nat_sip: translate all Via headers
2008-03-25 14:14 [METFILTER 00/32]: SIP helper update Patrick McHardy
` (22 preceding siblings ...)
2008-03-25 14:15 ` [NETFILTER 23/32]: nf_conntrack_sip: introduce URI and header parameter parsing helpers Patrick McHardy
@ 2008-03-25 14:15 ` Patrick McHardy
2008-03-25 14:15 ` [NETFILTER 25/32]: nf_nat_sip: translate all Contact headers Patrick McHardy
` (8 subsequent siblings)
32 siblings, 0 replies; 39+ messages in thread
From: Patrick McHardy @ 2008-03-25 14:15 UTC (permalink / raw)
To: davem; +Cc: Patrick McHardy, netfilter-devel
[NETFILTER]: nf_nat_sip: translate all Via headers
Update maddr=, received= and rport= Via-header parameters refering to
the signalling connection.
Signed-off-by: Patrick McHardy <kaber@trash.net>
---
commit eda29246d061965c8943f1a5954b056b3dc189fa
tree 958772517ac6a2e081c15db10e77c171c508fd8a
parent 2a21cab1320505abe9059adb8d42a130ea36e15b
author Patrick McHardy <kaber@trash.net> Tue, 25 Mar 2008 12:45:14 +0100
committer Patrick McHardy <kaber@trash.net> Tue, 25 Mar 2008 14:09:57 +0100
net/ipv4/netfilter/nf_nat_sip.c | 74 ++++++++++++++++++++++++++++++++++++++-
1 files changed, 73 insertions(+), 1 deletions(-)
diff --git a/net/ipv4/netfilter/nf_nat_sip.c b/net/ipv4/netfilter/nf_nat_sip.c
index b442810..71a4adc 100644
--- a/net/ipv4/netfilter/nf_nat_sip.c
+++ b/net/ipv4/netfilter/nf_nat_sip.c
@@ -100,9 +100,11 @@ static unsigned int ip_nat_sip(struct sk_buff *skb,
{
enum ip_conntrack_info ctinfo;
struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
+ enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
unsigned int matchoff, matchlen;
union nf_inet_addr addr;
__be16 port;
+ int request;
/* Basic rules: requests and responses. */
if (strnicmp(*dptr, "SIP/2.0", strlen("SIP/2.0")) != 0) {
@@ -112,11 +114,81 @@ static unsigned int ip_nat_sip(struct sk_buff *skb,
!map_addr(skb, dptr, datalen, matchoff, matchlen,
&addr, port))
return NF_DROP;
+ request = 1;
+ } else
+ request = 0;
+
+ /* Translate topmost Via header and parameters */
+ if (ct_sip_parse_header_uri(ct, *dptr, NULL, *datalen,
+ SIP_HDR_VIA, NULL, &matchoff, &matchlen,
+ &addr, &port) > 0) {
+ unsigned int matchend, poff, plen, buflen, n;
+ char buffer[sizeof("nnn.nnn.nnn.nnn:nnnnn")];
+
+ /* We're only interested in headers related to this
+ * connection */
+ if (request) {
+ if (addr.ip != ct->tuplehash[dir].tuple.src.u3.ip ||
+ port != ct->tuplehash[dir].tuple.src.u.udp.port)
+ goto next;
+ } else {
+ if (addr.ip != ct->tuplehash[dir].tuple.dst.u3.ip ||
+ port != ct->tuplehash[dir].tuple.dst.u.udp.port)
+ goto next;
+ }
+
+ if (!map_addr(skb, dptr, datalen, matchoff, matchlen,
+ &addr, port))
+ return NF_DROP;
+
+ matchend = matchoff + matchlen;
+
+ /* The maddr= parameter (RFC 2361) specifies where to send
+ * the reply. */
+ if (ct_sip_parse_address_param(ct, *dptr, matchend, *datalen,
+ "maddr=", &poff, &plen,
+ &addr) > 0 &&
+ addr.ip == ct->tuplehash[dir].tuple.src.u3.ip &&
+ addr.ip != ct->tuplehash[!dir].tuple.dst.u3.ip) {
+ __be32 ip = ct->tuplehash[!dir].tuple.dst.u3.ip;
+ buflen = sprintf(buffer, "%u.%u.%u.%u", NIPQUAD(ip));
+ if (!mangle_packet(skb, dptr, datalen, poff, plen,
+ buffer, buflen))
+ return NF_DROP;
+ }
+
+ /* The received= parameter (RFC 2361) contains the address
+ * from which the server received the request. */
+ if (ct_sip_parse_address_param(ct, *dptr, matchend, *datalen,
+ "received=", &poff, &plen,
+ &addr) > 0 &&
+ addr.ip == ct->tuplehash[dir].tuple.dst.u3.ip &&
+ addr.ip != ct->tuplehash[!dir].tuple.src.u3.ip) {
+ __be32 ip = ct->tuplehash[!dir].tuple.src.u3.ip;
+ buflen = sprintf(buffer, "%u.%u.%u.%u", NIPQUAD(ip));
+ if (!mangle_packet(skb, dptr, datalen, poff, plen,
+ buffer, buflen))
+ return NF_DROP;
+ }
+
+ /* The rport= parameter (RFC 3581) contains the port number
+ * from which the server received the request. */
+ if (ct_sip_parse_numerical_param(ct, *dptr, matchend, *datalen,
+ "rport=", &poff, &plen,
+ &n) > 0 &&
+ htons(n) == ct->tuplehash[dir].tuple.dst.u.udp.port &&
+ htons(n) != ct->tuplehash[!dir].tuple.src.u.udp.port) {
+ __be16 p = ct->tuplehash[!dir].tuple.src.u.udp.port;
+ buflen = sprintf(buffer, "%u", ntohs(p));
+ if (!mangle_packet(skb, dptr, datalen, poff, plen,
+ buffer, buflen))
+ return NF_DROP;
+ }
}
+next:
if (!map_sip_addr(skb, dptr, datalen, SIP_HDR_FROM) ||
!map_sip_addr(skb, dptr, datalen, SIP_HDR_TO) ||
- !map_sip_addr(skb, dptr, datalen, SIP_HDR_VIA) ||
!map_sip_addr(skb, dptr, datalen, SIP_HDR_CONTACT))
return NF_DROP;
return NF_ACCEPT;
^ permalink raw reply related [flat|nested] 39+ messages in thread* [NETFILTER 25/32]: nf_nat_sip: translate all Contact headers
2008-03-25 14:14 [METFILTER 00/32]: SIP helper update Patrick McHardy
` (23 preceding siblings ...)
2008-03-25 14:15 ` [NETFILTER 24/32]: nf_nat_sip: translate all Via headers Patrick McHardy
@ 2008-03-25 14:15 ` Patrick McHardy
2008-03-25 14:15 ` [NETFILTER 26/32]: nf_conntrack_sip: create signalling expectations Patrick McHardy
` (7 subsequent siblings)
32 siblings, 0 replies; 39+ messages in thread
From: Patrick McHardy @ 2008-03-25 14:15 UTC (permalink / raw)
To: davem; +Cc: Patrick McHardy, netfilter-devel
[NETFILTER]: nf_nat_sip: translate all Contact headers
The SIP message may contain multiple Contact: addresses referring to
the NATed endpoint, translate all of them.
Signed-off-by: Patrick McHardy <kaber@trash.net>
---
commit 8f15ab436de825574920db877a18917979712df4
tree 062b48ee051c4599b0425722c389c6eea4426b5c
parent eda29246d061965c8943f1a5954b056b3dc189fa
author Patrick McHardy <kaber@trash.net> Tue, 25 Mar 2008 12:45:16 +0100
committer Patrick McHardy <kaber@trash.net> Tue, 25 Mar 2008 14:09:58 +0100
net/ipv4/netfilter/nf_nat_sip.c | 19 +++++++++++++++----
1 files changed, 15 insertions(+), 4 deletions(-)
diff --git a/net/ipv4/netfilter/nf_nat_sip.c b/net/ipv4/netfilter/nf_nat_sip.c
index 71a4adc..b443618 100644
--- a/net/ipv4/netfilter/nf_nat_sip.c
+++ b/net/ipv4/netfilter/nf_nat_sip.c
@@ -101,10 +101,10 @@ static unsigned int ip_nat_sip(struct sk_buff *skb,
enum ip_conntrack_info ctinfo;
struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
- unsigned int matchoff, matchlen;
+ unsigned int dataoff, matchoff, matchlen;
union nf_inet_addr addr;
__be16 port;
- int request;
+ int request, in_header;
/* Basic rules: requests and responses. */
if (strnicmp(*dptr, "SIP/2.0", strlen("SIP/2.0")) != 0) {
@@ -187,9 +187,20 @@ static unsigned int ip_nat_sip(struct sk_buff *skb,
}
next:
+ /* Translate Contact headers */
+ dataoff = 0;
+ in_header = 0;
+ while (ct_sip_parse_header_uri(ct, *dptr, &dataoff, *datalen,
+ SIP_HDR_CONTACT, &in_header,
+ &matchoff, &matchlen,
+ &addr, &port) > 0) {
+ if (!map_addr(skb, dptr, datalen, matchoff, matchlen,
+ &addr, port))
+ return NF_DROP;
+ }
+
if (!map_sip_addr(skb, dptr, datalen, SIP_HDR_FROM) ||
- !map_sip_addr(skb, dptr, datalen, SIP_HDR_TO) ||
- !map_sip_addr(skb, dptr, datalen, SIP_HDR_CONTACT))
+ !map_sip_addr(skb, dptr, datalen, SIP_HDR_TO))
return NF_DROP;
return NF_ACCEPT;
}
^ permalink raw reply related [flat|nested] 39+ messages in thread* [NETFILTER 26/32]: nf_conntrack_sip: create signalling expectations
2008-03-25 14:14 [METFILTER 00/32]: SIP helper update Patrick McHardy
` (24 preceding siblings ...)
2008-03-25 14:15 ` [NETFILTER 25/32]: nf_nat_sip: translate all Contact headers Patrick McHardy
@ 2008-03-25 14:15 ` Patrick McHardy
2008-03-25 14:15 ` [NETFILTER 27/32]: nf_conntrack_sip: allow media expectations with wildcard source address Patrick McHardy
` (6 subsequent siblings)
32 siblings, 0 replies; 39+ messages in thread
From: Patrick McHardy @ 2008-03-25 14:15 UTC (permalink / raw)
To: davem; +Cc: Patrick McHardy, netfilter-devel
[NETFILTER]: nf_conntrack_sip: create signalling expectations
Create expectations for incoming signalling connections when seeing
a REGISTER request. This is needed when the registrar uses a
different source port number for signalling messages and for receiving
incoming calls from other endpoints than the registrar.
Signed-off-by: Patrick McHardy <kaber@trash.net>
---
commit ddd1dea3c44ea5bfd6d63048ad5013f27c76136a
tree 71939d7d4cc84e8a28b4510ebe0f4e15a3e7011e
parent 8f15ab436de825574920db877a18917979712df4
author Patrick McHardy <kaber@trash.net> Tue, 25 Mar 2008 12:45:17 +0100
committer Patrick McHardy <kaber@trash.net> Tue, 25 Mar 2008 14:09:58 +0100
include/linux/netfilter/nf_conntrack_sip.h | 18 ++
include/net/netfilter/nf_conntrack.h | 4
net/ipv4/netfilter/nf_nat_sip.c | 111 +++++++++++--
net/netfilter/nf_conntrack_sip.c | 232 +++++++++++++++++++++++++++-
4 files changed, 332 insertions(+), 33 deletions(-)
diff --git a/include/linux/netfilter/nf_conntrack_sip.h b/include/linux/netfilter/nf_conntrack_sip.h
index 87e4028..7cc84ed 100644
--- a/include/linux/netfilter/nf_conntrack_sip.h
+++ b/include/linux/netfilter/nf_conntrack_sip.h
@@ -5,6 +5,17 @@
#define SIP_PORT 5060
#define SIP_TIMEOUT 3600
+struct nf_ct_sip_master {
+ unsigned int register_cseq;
+};
+
+enum sip_expectation_classes {
+ SIP_EXPECT_SIGNALLING,
+ SIP_EXPECT_AUDIO,
+ __SIP_EXPECT_MAX
+};
+#define SIP_EXPECT_MAX (__SIP_EXPECT_MAX - 1)
+
struct sip_handler {
const char *method;
unsigned int len;
@@ -59,6 +70,7 @@ enum sip_header_types {
SIP_HDR_TO,
SIP_HDR_CONTACT,
SIP_HDR_VIA,
+ SIP_HDR_EXPIRES,
SIP_HDR_CONTENT_LENGTH,
};
@@ -75,6 +87,12 @@ enum sdp_header_types {
extern unsigned int (*nf_nat_sip_hook)(struct sk_buff *skb,
const char **dptr,
unsigned int *datalen);
+extern unsigned int (*nf_nat_sip_expect_hook)(struct sk_buff *skb,
+ const char **dptr,
+ unsigned int *datalen,
+ struct nf_conntrack_expect *exp,
+ unsigned int matchoff,
+ unsigned int matchlen);
extern unsigned int (*nf_nat_sdp_hook)(struct sk_buff *skb,
const char **dptr,
unsigned int *datalen,
diff --git a/include/net/netfilter/nf_conntrack.h b/include/net/netfilter/nf_conntrack.h
index 9228771..4a4f870 100644
--- a/include/net/netfilter/nf_conntrack.h
+++ b/include/net/netfilter/nf_conntrack.h
@@ -46,6 +46,7 @@ union nf_conntrack_expect_proto {
#include <linux/netfilter/nf_conntrack_pptp.h>
#include <linux/netfilter/nf_conntrack_h323.h>
#include <linux/netfilter/nf_conntrack_sane.h>
+#include <linux/netfilter/nf_conntrack_sip.h>
/* per conntrack: application helper private data */
union nf_conntrack_help {
@@ -54,6 +55,7 @@ union nf_conntrack_help {
struct nf_ct_pptp_master ct_pptp_info;
struct nf_ct_h323_master ct_h323_info;
struct nf_ct_sane_master ct_sane_info;
+ struct nf_ct_sip_master ct_sip_info;
};
#include <linux/types.h>
@@ -76,7 +78,7 @@ do { \
struct nf_conntrack_helper;
/* Must be kept in sync with the classes defined by helpers */
-#define NF_CT_MAX_EXPECT_CLASSES 1
+#define NF_CT_MAX_EXPECT_CLASSES 2
/* nf_conn feature for connections that have a helper */
struct nf_conn_help {
diff --git a/net/ipv4/netfilter/nf_nat_sip.c b/net/ipv4/netfilter/nf_nat_sip.c
index b443618..4b85e21 100644
--- a/net/ipv4/netfilter/nf_nat_sip.c
+++ b/net/ipv4/netfilter/nf_nat_sip.c
@@ -205,6 +205,91 @@ next:
return NF_ACCEPT;
}
+/* Handles expected signalling connections and media streams */
+static void ip_nat_sip_expected(struct nf_conn *ct,
+ struct nf_conntrack_expect *exp)
+{
+ struct nf_nat_range range;
+
+ /* This must be a fresh one. */
+ BUG_ON(ct->status & IPS_NAT_DONE_MASK);
+
+ /* For DST manip, map port here to where it's expected. */
+ range.flags = (IP_NAT_RANGE_MAP_IPS | IP_NAT_RANGE_PROTO_SPECIFIED);
+ range.min = range.max = exp->saved_proto;
+ range.min_ip = range.max_ip = exp->saved_ip;
+ nf_nat_setup_info(ct, &range, IP_NAT_MANIP_DST);
+
+ /* Change src to where master sends to, but only if the connection
+ * actually came from the same source. */
+ if (ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u3.ip ==
+ ct->master->tuplehash[exp->dir].tuple.src.u3.ip) {
+ range.flags = IP_NAT_RANGE_MAP_IPS;
+ range.min_ip = range.max_ip
+ = ct->master->tuplehash[!exp->dir].tuple.dst.u3.ip;
+ nf_nat_setup_info(ct, &range, IP_NAT_MANIP_SRC);
+ }
+}
+
+static unsigned int ip_nat_sip_expect(struct sk_buff *skb,
+ const char **dptr, unsigned int *datalen,
+ struct nf_conntrack_expect *exp,
+ unsigned int matchoff,
+ unsigned int matchlen)
+{
+ enum ip_conntrack_info ctinfo;
+ struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
+ enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
+ __be32 newip;
+ u_int16_t port;
+ char buffer[sizeof("nnn.nnn.nnn.nnn:nnnnn")];
+ unsigned buflen;
+
+ /* Connection will come from reply */
+ if (ct->tuplehash[dir].tuple.src.u3.ip == ct->tuplehash[!dir].tuple.dst.u3.ip)
+ newip = exp->tuple.dst.u3.ip;
+ else
+ newip = ct->tuplehash[!dir].tuple.dst.u3.ip;
+
+ /* If the signalling port matches the connection's source port in the
+ * original direction, try to use the destination port in the opposite
+ * direction. */
+ if (exp->tuple.dst.u.udp.port ==
+ ct->tuplehash[dir].tuple.src.u.udp.port)
+ port = ntohs(ct->tuplehash[!dir].tuple.dst.u.udp.port);
+ else
+ port = ntohs(exp->tuple.dst.u.udp.port);
+
+ exp->saved_ip = exp->tuple.dst.u3.ip;
+ exp->tuple.dst.u3.ip = newip;
+ exp->saved_proto.udp.port = exp->tuple.dst.u.udp.port;
+ exp->dir = !dir;
+ exp->expectfn = ip_nat_sip_expected;
+
+ for (; port != 0; port++) {
+ exp->tuple.dst.u.udp.port = htons(port);
+ if (nf_ct_expect_related(exp) == 0)
+ break;
+ }
+
+ if (port == 0)
+ return NF_DROP;
+
+ if (exp->tuple.dst.u3.ip != exp->saved_ip ||
+ exp->tuple.dst.u.udp.port != exp->saved_proto.udp.port) {
+ buflen = sprintf(buffer, "%u.%u.%u.%u:%u",
+ NIPQUAD(newip), port);
+ if (!mangle_packet(skb, dptr, datalen, matchoff, matchlen,
+ buffer, buflen))
+ goto err;
+ }
+ return NF_ACCEPT;
+
+err:
+ nf_ct_unexpect_related(exp);
+ return NF_DROP;
+}
+
static int mangle_content_len(struct sk_buff *skb,
const char **dptr, unsigned int *datalen)
{
@@ -275,27 +360,6 @@ static unsigned int mangle_sdp(struct sk_buff *skb,
return mangle_content_len(skb, dptr, datalen);
}
-static void ip_nat_sdp_expect(struct nf_conn *ct,
- struct nf_conntrack_expect *exp)
-{
- struct nf_nat_range range;
-
- /* This must be a fresh one. */
- BUG_ON(ct->status & IPS_NAT_DONE_MASK);
-
- /* For DST manip, map port here to where it's expected. */
- range.flags = (IP_NAT_RANGE_MAP_IPS | IP_NAT_RANGE_PROTO_SPECIFIED);
- range.min = range.max = exp->saved_proto;
- range.min_ip = range.max_ip = exp->saved_ip;
- nf_nat_setup_info(ct, &range, IP_NAT_MANIP_DST);
-
- /* Change src to where master sends to */
- range.flags = IP_NAT_RANGE_MAP_IPS;
- range.min_ip = range.max_ip
- = ct->master->tuplehash[!exp->dir].tuple.dst.u3.ip;
- nf_nat_setup_info(ct, &range, IP_NAT_MANIP_SRC);
-}
-
/* So, this packet has hit the connection tracking matching code.
Mangle it, and change the expectation to match the new version. */
static unsigned int ip_nat_sdp(struct sk_buff *skb,
@@ -322,7 +386,7 @@ static unsigned int ip_nat_sdp(struct sk_buff *skb,
/* When you see the packet, we need to NAT it the same as the
this one. */
- exp->expectfn = ip_nat_sdp_expect;
+ exp->expectfn = ip_nat_sip_expected;
/* Try to get same port: if not, try to change it. */
for (port = ntohs(exp->saved_proto.udp.port); port != 0; port++) {
@@ -344,6 +408,7 @@ static unsigned int ip_nat_sdp(struct sk_buff *skb,
static void __exit nf_nat_sip_fini(void)
{
rcu_assign_pointer(nf_nat_sip_hook, NULL);
+ rcu_assign_pointer(nf_nat_sip_expect_hook, NULL);
rcu_assign_pointer(nf_nat_sdp_hook, NULL);
synchronize_rcu();
}
@@ -351,8 +416,10 @@ static void __exit nf_nat_sip_fini(void)
static int __init nf_nat_sip_init(void)
{
BUG_ON(nf_nat_sip_hook != NULL);
+ BUG_ON(nf_nat_sip_expect_hook != NULL);
BUG_ON(nf_nat_sdp_hook != NULL);
rcu_assign_pointer(nf_nat_sip_hook, ip_nat_sip);
+ rcu_assign_pointer(nf_nat_sip_expect_hook, ip_nat_sip_expect);
rcu_assign_pointer(nf_nat_sdp_hook, ip_nat_sdp);
return 0;
}
diff --git a/net/netfilter/nf_conntrack_sip.c b/net/netfilter/nf_conntrack_sip.c
index 126f308..043aa55 100644
--- a/net/netfilter/nf_conntrack_sip.c
+++ b/net/netfilter/nf_conntrack_sip.c
@@ -37,11 +37,24 @@ static unsigned int sip_timeout __read_mostly = SIP_TIMEOUT;
module_param(sip_timeout, uint, 0600);
MODULE_PARM_DESC(sip_timeout, "timeout for the master SIP session");
+static int sip_direct_signalling __read_mostly = 1;
+module_param(sip_direct_signalling, int, 0600);
+MODULE_PARM_DESC(sip_direct_signalling, "expect incoming calls from registrar "
+ "only (default 1)");
+
unsigned int (*nf_nat_sip_hook)(struct sk_buff *skb,
const char **dptr,
unsigned int *datalen) __read_mostly;
EXPORT_SYMBOL_GPL(nf_nat_sip_hook);
+unsigned int (*nf_nat_sip_expect_hook)(struct sk_buff *skb,
+ const char **dptr,
+ unsigned int *datalen,
+ struct nf_conntrack_expect *exp,
+ unsigned int matchoff,
+ unsigned int matchlen) __read_mostly;
+EXPORT_SYMBOL_GPL(nf_nat_sip_expect_hook);
+
unsigned int (*nf_nat_sdp_hook)(struct sk_buff *skb,
const char **dptr,
unsigned int *datalen,
@@ -218,6 +231,7 @@ static const struct sip_header ct_sip_hdrs[] = {
[SIP_HDR_TO] = SIP_HDR("To", "t", "sip:", skp_epaddr_len),
[SIP_HDR_CONTACT] = SIP_HDR("Contact", "m", "sip:", skp_epaddr_len),
[SIP_HDR_VIA] = SIP_HDR("Via", "v", "UDP ", epaddr_len),
+ [SIP_HDR_EXPIRES] = SIP_HDR("Expires", NULL, NULL, digits_len),
[SIP_HDR_CONTENT_LENGTH] = SIP_HDR("Content-Length", "l", NULL, digits_len),
};
@@ -592,18 +606,50 @@ int ct_sip_get_sdp_header(const struct nf_conn *ct, const char *dptr,
}
EXPORT_SYMBOL_GPL(ct_sip_get_sdp_header);
-static void flush_expectations(struct nf_conn *ct)
+static int refresh_signalling_expectation(struct nf_conn *ct,
+ union nf_inet_addr *addr,
+ __be16 port,
+ unsigned int expires)
{
struct nf_conn_help *help = nfct_help(ct);
struct nf_conntrack_expect *exp;
struct hlist_node *n, *next;
+ int found = 0;
spin_lock_bh(&nf_conntrack_lock);
hlist_for_each_entry_safe(exp, n, next, &help->expectations, lnode) {
+ if (exp->class != SIP_EXPECT_SIGNALLING ||
+ !nf_inet_addr_cmp(&exp->tuple.dst.u3, addr) ||
+ exp->tuple.dst.u.udp.port != port)
+ continue;
+ if (!del_timer(&exp->timeout))
+ continue;
+ exp->flags &= ~NF_CT_EXPECT_INACTIVE;
+ exp->timeout.expires = jiffies + expires * HZ;
+ add_timer(&exp->timeout);
+ found = 1;
+ break;
+ }
+ spin_unlock_bh(&nf_conntrack_lock);
+ return found;
+}
+
+static void flush_expectations(struct nf_conn *ct, bool media)
+{
+ struct nf_conn_help *help = nfct_help(ct);
+ struct nf_conntrack_expect *exp;
+ struct hlist_node *n, *next;
+
+ spin_lock_bh(&nf_conntrack_lock);
+ hlist_for_each_entry_safe(exp, n, next, &help->expectations, lnode) {
+ if ((exp->class != SIP_EXPECT_SIGNALLING) ^ media)
+ continue;
if (!del_timer(&exp->timeout))
continue;
nf_ct_unlink_expect(exp);
nf_ct_expect_put(exp);
+ if (!media)
+ break;
}
spin_unlock_bh(&nf_conntrack_lock);
}
@@ -623,7 +669,7 @@ static int set_expected_rtp(struct sk_buff *skb,
exp = nf_ct_expect_alloc(ct);
if (exp == NULL)
return NF_DROP;
- nf_ct_expect_init(exp, NF_CT_EXPECT_CLASS_DEFAULT, family,
+ nf_ct_expect_init(exp, SIP_EXPECT_AUDIO, family,
&ct->tuplehash[!dir].tuple.src.u3, addr,
IPPROTO_UDP, NULL, &port);
@@ -688,7 +734,7 @@ static int process_invite_response(struct sk_buff *skb,
(code >= 200 && code <= 299))
return process_sdp(skb, dptr, datalen, cseq);
else {
- flush_expectations(ct);
+ flush_expectations(ct, true);
return NF_ACCEPT;
}
}
@@ -704,7 +750,7 @@ static int process_update_response(struct sk_buff *skb,
(code >= 200 && code <= 299))
return process_sdp(skb, dptr, datalen, cseq);
else {
- flush_expectations(ct);
+ flush_expectations(ct, true);
return NF_ACCEPT;
}
}
@@ -720,7 +766,7 @@ static int process_prack_response(struct sk_buff *skb,
(code >= 200 && code <= 299))
return process_sdp(skb, dptr, datalen, cseq);
else {
- flush_expectations(ct);
+ flush_expectations(ct, true);
return NF_ACCEPT;
}
}
@@ -732,7 +778,165 @@ static int process_bye_request(struct sk_buff *skb,
enum ip_conntrack_info ctinfo;
struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
- flush_expectations(ct);
+ flush_expectations(ct, true);
+ return NF_ACCEPT;
+}
+
+/* Parse a REGISTER request and create a permanent expectation for incoming
+ * signalling connections. The expectation is marked inactive and is activated
+ * when receiving a response indicating success from the registrar.
+ */
+static int process_register_request(struct sk_buff *skb,
+ const char **dptr, unsigned int *datalen,
+ unsigned int cseq)
+{
+ enum ip_conntrack_info ctinfo;
+ struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
+ struct nf_conn_help *help = nfct_help(ct);
+ enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
+ int family = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.l3num;
+ unsigned int matchoff, matchlen;
+ struct nf_conntrack_expect *exp;
+ union nf_inet_addr *saddr, daddr;
+ __be16 port;
+ unsigned int expires = 0;
+ int ret;
+ typeof(nf_nat_sip_expect_hook) nf_nat_sip_expect;
+
+ /* Expected connections can not register again. */
+ if (ct->status & IPS_EXPECTED)
+ return NF_ACCEPT;
+
+ /* We must check the expiration time: a value of zero signals the
+ * registrar to release the binding. We'll remove our expectation
+ * when receiving the new bindings in the response, but we don't
+ * want to create new ones.
+ *
+ * The expiration time may be contained in Expires: header, the
+ * Contact: header parameters or the URI parameters.
+ */
+ if (ct_sip_get_header(ct, *dptr, 0, *datalen, SIP_HDR_EXPIRES,
+ &matchoff, &matchlen) > 0)
+ expires = simple_strtoul(*dptr + matchoff, NULL, 10);
+
+ ret = ct_sip_parse_header_uri(ct, *dptr, NULL, *datalen,
+ SIP_HDR_CONTACT, NULL,
+ &matchoff, &matchlen, &daddr, &port);
+ if (ret < 0)
+ return NF_DROP;
+ else if (ret == 0)
+ return NF_ACCEPT;
+
+ /* We don't support third-party registrations */
+ if (!nf_inet_addr_cmp(&ct->tuplehash[dir].tuple.src.u3, &daddr))
+ return NF_ACCEPT;
+
+ if (ct_sip_parse_numerical_param(ct, *dptr,
+ matchoff + matchlen, *datalen,
+ "expires=", NULL, NULL, &expires) < 0)
+ return NF_DROP;
+
+ if (expires == 0) {
+ ret = NF_ACCEPT;
+ goto store_cseq;
+ }
+
+ exp = nf_ct_expect_alloc(ct);
+ if (!exp)
+ return NF_DROP;
+
+ saddr = NULL;
+ if (sip_direct_signalling)
+ saddr = &ct->tuplehash[!dir].tuple.src.u3;
+
+ nf_ct_expect_init(exp, SIP_EXPECT_SIGNALLING, family, saddr, &daddr,
+ IPPROTO_UDP, NULL, &port);
+ exp->timeout.expires = sip_timeout * HZ;
+ exp->helper = nfct_help(ct)->helper;
+ exp->flags = NF_CT_EXPECT_PERMANENT | NF_CT_EXPECT_INACTIVE;
+
+ nf_nat_sip_expect = rcu_dereference(nf_nat_sip_expect_hook);
+ if (nf_nat_sip_expect && ct->status & IPS_NAT_MASK)
+ ret = nf_nat_sip_expect(skb, dptr, datalen, exp,
+ matchoff, matchlen);
+ else {
+ if (nf_ct_expect_related(exp) != 0)
+ ret = NF_DROP;
+ else
+ ret = NF_ACCEPT;
+ }
+ nf_ct_expect_put(exp);
+
+store_cseq:
+ if (ret == NF_ACCEPT)
+ help->help.ct_sip_info.register_cseq = cseq;
+ return ret;
+}
+
+static int process_register_response(struct sk_buff *skb,
+ const char **dptr, unsigned int *datalen,
+ unsigned int cseq, unsigned int code)
+{
+ enum ip_conntrack_info ctinfo;
+ struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
+ struct nf_conn_help *help = nfct_help(ct);
+ enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
+ union nf_inet_addr addr;
+ __be16 port;
+ unsigned int matchoff, matchlen, dataoff = 0;
+ unsigned int expires = 0;
+ int in_contact = 0, ret;
+
+ /* According to RFC 3261, "UAs MUST NOT send a new registration until
+ * they have received a final response from the registrar for the
+ * previous one or the previous REGISTER request has timed out".
+ *
+ * However, some servers fail to detect retransmissions and send late
+ * responses, so we store the sequence number of the last valid
+ * request and compare it here.
+ */
+ if (help->help.ct_sip_info.register_cseq != cseq)
+ return NF_ACCEPT;
+
+ if (code >= 100 && code <= 199)
+ return NF_ACCEPT;
+ if (code < 200 || code > 299)
+ goto flush;
+
+ if (ct_sip_get_header(ct, *dptr, 0, *datalen, SIP_HDR_EXPIRES,
+ &matchoff, &matchlen) > 0)
+ expires = simple_strtoul(*dptr + matchoff, NULL, 10);
+
+ while (1) {
+ unsigned int c_expires = expires;
+
+ ret = ct_sip_parse_header_uri(ct, *dptr, &dataoff, *datalen,
+ SIP_HDR_CONTACT, &in_contact,
+ &matchoff, &matchlen,
+ &addr, &port);
+ if (ret < 0)
+ return NF_DROP;
+ else if (ret == 0)
+ break;
+
+ /* We don't support third-party registrations */
+ if (!nf_inet_addr_cmp(&ct->tuplehash[dir].tuple.dst.u3, &addr))
+ continue;
+
+ ret = ct_sip_parse_numerical_param(ct, *dptr,
+ matchoff + matchlen,
+ *datalen, "expires=",
+ NULL, NULL, &c_expires);
+ if (ret < 0)
+ return NF_DROP;
+ if (c_expires == 0)
+ break;
+ if (refresh_signalling_expectation(ct, &addr, port, c_expires))
+ return NF_ACCEPT;
+ }
+
+flush:
+ flush_expectations(ct, false);
return NF_ACCEPT;
}
@@ -742,6 +946,7 @@ static const struct sip_handler sip_handlers[] = {
SIP_HANDLER("ACK", process_sdp, NULL),
SIP_HANDLER("PRACK", process_sdp, process_prack_response),
SIP_HANDLER("BYE", process_bye_request, NULL),
+ SIP_HANDLER("REGISTER", process_register_request, process_register_response),
};
static int process_sip_response(struct sk_buff *skb,
@@ -853,9 +1058,15 @@ static int sip_help(struct sk_buff *skb,
static struct nf_conntrack_helper sip[MAX_PORTS][2] __read_mostly;
static char sip_names[MAX_PORTS][2][sizeof("sip-65535")] __read_mostly;
-static const struct nf_conntrack_expect_policy sip_exp_policy = {
- .max_expected = 2,
- .timeout = 3 * 60,
+static const struct nf_conntrack_expect_policy sip_exp_policy[SIP_EXPECT_MAX + 1] = {
+ [SIP_EXPECT_SIGNALLING] = {
+ .max_expected = 1,
+ .timeout = 3 * 60,
+ },
+ [SIP_EXPECT_AUDIO] = {
+ .max_expected = IP_CT_DIR_MAX,
+ .timeout = 3 * 60,
+ },
};
static void nf_conntrack_sip_fini(void)
@@ -887,7 +1098,8 @@ static int __init nf_conntrack_sip_init(void)
for (j = 0; j < 2; j++) {
sip[i][j].tuple.dst.protonum = IPPROTO_UDP;
sip[i][j].tuple.src.u.udp.port = htons(ports[i]);
- sip[i][j].expect_policy = &sip_exp_policy;
+ sip[i][j].expect_policy = sip_exp_policy;
+ sip[i][j].expect_class_max = SIP_EXPECT_MAX;
sip[i][j].me = THIS_MODULE;
sip[i][j].help = sip_help;
^ permalink raw reply related [flat|nested] 39+ messages in thread* [NETFILTER 27/32]: nf_conntrack_sip: allow media expectations with wildcard source address
2008-03-25 14:14 [METFILTER 00/32]: SIP helper update Patrick McHardy
` (25 preceding siblings ...)
2008-03-25 14:15 ` [NETFILTER 26/32]: nf_conntrack_sip: create signalling expectations Patrick McHardy
@ 2008-03-25 14:15 ` Patrick McHardy
2008-03-25 14:15 ` [NETFILTER 28/32]: nf_conntrack_sip: create RTCP expectations Patrick McHardy
` (5 subsequent siblings)
32 siblings, 0 replies; 39+ messages in thread
From: Patrick McHardy @ 2008-03-25 14:15 UTC (permalink / raw)
To: davem; +Cc: Patrick McHardy, netfilter-devel
[NETFILTER]: nf_conntrack_sip: allow media expectations with wildcard source address
Media streams can come from anywhere, add a module parameter which
controls whether wildcard expectations or expectations between the
two signalling endpoints are created.
Since the same media description sent on multiple connections may
results in multiple identical expections when using a wildcard source,
we need to check whether a similar expectation already exists for a
different connection before attempting to register it.
Signed-off-by: Patrick McHardy <kaber@trash.net>
---
commit 61ca069c85c8b4a110143b1a1ae3263d6dd60945
tree 09a09361781b17e5bbf9bde939eab99656761b0a
parent ddd1dea3c44ea5bfd6d63048ad5013f27c76136a
author Patrick McHardy <kaber@trash.net> Tue, 25 Mar 2008 12:45:19 +0100
committer Patrick McHardy <kaber@trash.net> Tue, 25 Mar 2008 14:09:58 +0100
net/netfilter/nf_conntrack_sip.c | 45 +++++++++++++++++++++++++++++++++++---
1 files changed, 41 insertions(+), 4 deletions(-)
diff --git a/net/netfilter/nf_conntrack_sip.c b/net/netfilter/nf_conntrack_sip.c
index 043aa55..813aa8c 100644
--- a/net/netfilter/nf_conntrack_sip.c
+++ b/net/netfilter/nf_conntrack_sip.c
@@ -42,6 +42,11 @@ module_param(sip_direct_signalling, int, 0600);
MODULE_PARM_DESC(sip_direct_signalling, "expect incoming calls from registrar "
"only (default 1)");
+static int sip_direct_media __read_mostly = 1;
+module_param(sip_direct_media, int, 0600);
+MODULE_PARM_DESC(sip_direct_media, "Expect Media streams between signalling "
+ "endpoints only (default 1)");
+
unsigned int (*nf_nat_sip_hook)(struct sk_buff *skb,
const char **dptr,
unsigned int *datalen) __read_mostly;
@@ -656,21 +661,53 @@ static void flush_expectations(struct nf_conn *ct, bool media)
static int set_expected_rtp(struct sk_buff *skb,
const char **dptr, unsigned int *datalen,
- union nf_inet_addr *addr, __be16 port)
+ union nf_inet_addr *daddr, __be16 port)
{
struct nf_conntrack_expect *exp;
enum ip_conntrack_info ctinfo;
struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
+ union nf_inet_addr *saddr;
+ struct nf_conntrack_tuple tuple;
int family = ct->tuplehash[!dir].tuple.src.l3num;
- int ret;
+ int skip_expect = 0, ret;
typeof(nf_nat_sdp_hook) nf_nat_sdp;
+ saddr = NULL;
+ if (sip_direct_media) {
+ if (!nf_inet_addr_cmp(daddr, &ct->tuplehash[dir].tuple.src.u3))
+ return NF_ACCEPT;
+ saddr = &ct->tuplehash[!dir].tuple.src.u3;
+ }
+
+ /* We need to check whether the registration exists before attempting
+ * to register it since we can see the same media description multiple
+ * times on different connections in case multiple endpoints receive
+ * the same call.
+ */
+ memset(&tuple, 0, sizeof(tuple));
+ if (saddr)
+ tuple.src.u3 = *saddr;
+ tuple.src.l3num = family;
+ tuple.dst.protonum = IPPROTO_UDP;
+ tuple.dst.u3 = *daddr;
+ tuple.dst.u.udp.port = port;
+
+ rcu_read_lock();
+ exp = __nf_ct_expect_find(&tuple);
+ if (exp && exp->master != ct &&
+ nfct_help(exp->master)->helper == nfct_help(ct)->helper &&
+ exp->class == SIP_EXPECT_AUDIO)
+ skip_expect = 1;
+ rcu_read_unlock();
+
+ if (skip_expect)
+ return NF_ACCEPT;
+
exp = nf_ct_expect_alloc(ct);
if (exp == NULL)
return NF_DROP;
- nf_ct_expect_init(exp, SIP_EXPECT_AUDIO, family,
- &ct->tuplehash[!dir].tuple.src.u3, addr,
+ nf_ct_expect_init(exp, SIP_EXPECT_AUDIO, family, saddr, daddr,
IPPROTO_UDP, NULL, &port);
nf_nat_sdp = rcu_dereference(nf_nat_sdp_hook);
^ permalink raw reply related [flat|nested] 39+ messages in thread* [NETFILTER 28/32]: nf_conntrack_sip: create RTCP expectations
2008-03-25 14:14 [METFILTER 00/32]: SIP helper update Patrick McHardy
` (26 preceding siblings ...)
2008-03-25 14:15 ` [NETFILTER 27/32]: nf_conntrack_sip: allow media expectations with wildcard source address Patrick McHardy
@ 2008-03-25 14:15 ` Patrick McHardy
2008-03-25 14:15 ` [NETFILTER 29/32]: nf_nat_sip: split up SDP mangling Patrick McHardy
` (4 subsequent siblings)
32 siblings, 0 replies; 39+ messages in thread
From: Patrick McHardy @ 2008-03-25 14:15 UTC (permalink / raw)
To: davem; +Cc: Patrick McHardy, netfilter-devel
[NETFILTER]: nf_conntrack_sip: create RTCP expectations
Create expectations for the RTCP connections in addition to RTP connections.
Signed-off-by: Patrick McHardy <kaber@trash.net>
---
commit bd085bafc458c50d639e3997fdff52fc457173ba
tree a4874ee96d70bb10f8dfadd1838065616dad240c
parent 61ca069c85c8b4a110143b1a1ae3263d6dd60945
author Patrick McHardy <kaber@trash.net> Tue, 25 Mar 2008 12:45:20 +0100
committer Patrick McHardy <kaber@trash.net> Tue, 25 Mar 2008 14:09:58 +0100
include/linux/netfilter/nf_conntrack_sip.h | 3 +
net/ipv4/netfilter/nf_nat_sip.c | 42 +++++++++++++-------
net/netfilter/nf_conntrack_sip.c | 58 ++++++++++++++++++----------
3 files changed, 66 insertions(+), 37 deletions(-)
diff --git a/include/linux/netfilter/nf_conntrack_sip.h b/include/linux/netfilter/nf_conntrack_sip.h
index 7cc84ed..6ddf95f 100644
--- a/include/linux/netfilter/nf_conntrack_sip.h
+++ b/include/linux/netfilter/nf_conntrack_sip.h
@@ -96,7 +96,8 @@ extern unsigned int (*nf_nat_sip_expect_hook)(struct sk_buff *skb,
extern unsigned int (*nf_nat_sdp_hook)(struct sk_buff *skb,
const char **dptr,
unsigned int *datalen,
- struct nf_conntrack_expect *exp);
+ struct nf_conntrack_expect *rtp_exp,
+ struct nf_conntrack_expect *rtcp_exp);
extern int ct_sip_parse_request(const struct nf_conn *ct,
const char *dptr, unsigned int datalen,
diff --git a/net/ipv4/netfilter/nf_nat_sip.c b/net/ipv4/netfilter/nf_nat_sip.c
index 4b85e21..f73ab48 100644
--- a/net/ipv4/netfilter/nf_nat_sip.c
+++ b/net/ipv4/netfilter/nf_nat_sip.c
@@ -364,7 +364,8 @@ static unsigned int mangle_sdp(struct sk_buff *skb,
Mangle it, and change the expectation to match the new version. */
static unsigned int ip_nat_sdp(struct sk_buff *skb,
const char **dptr, unsigned int *datalen,
- struct nf_conntrack_expect *exp)
+ struct nf_conntrack_expect *rtp_exp,
+ struct nf_conntrack_expect *rtcp_exp)
{
enum ip_conntrack_info ctinfo;
struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
@@ -375,31 +376,40 @@ static unsigned int ip_nat_sdp(struct sk_buff *skb,
/* Connection will come from reply */
if (ct->tuplehash[dir].tuple.src.u3.ip ==
ct->tuplehash[!dir].tuple.dst.u3.ip)
- newip = exp->tuple.dst.u3.ip;
+ newip = rtp_exp->tuple.dst.u3.ip;
else
newip = ct->tuplehash[!dir].tuple.dst.u3.ip;
- exp->saved_ip = exp->tuple.dst.u3.ip;
- exp->tuple.dst.u3.ip = newip;
- exp->saved_proto.udp.port = exp->tuple.dst.u.udp.port;
- exp->dir = !dir;
-
- /* When you see the packet, we need to NAT it the same as the
- this one. */
- exp->expectfn = ip_nat_sip_expected;
-
- /* Try to get same port: if not, try to change it. */
- for (port = ntohs(exp->saved_proto.udp.port); port != 0; port++) {
- exp->tuple.dst.u.udp.port = htons(port);
- if (nf_ct_expect_related(exp) == 0)
+ rtp_exp->saved_ip = rtp_exp->tuple.dst.u3.ip;
+ rtp_exp->tuple.dst.u3.ip = newip;
+ rtp_exp->saved_proto.udp.port = rtp_exp->tuple.dst.u.udp.port;
+ rtp_exp->dir = !dir;
+ rtp_exp->expectfn = ip_nat_sip_expected;
+
+ rtcp_exp->saved_ip = rtcp_exp->tuple.dst.u3.ip;
+ rtcp_exp->tuple.dst.u3.ip = newip;
+ rtcp_exp->saved_proto.udp.port = rtcp_exp->tuple.dst.u.udp.port;
+ rtcp_exp->dir = !dir;
+ rtcp_exp->expectfn = ip_nat_sip_expected;
+
+ /* Try to get same pair of ports: if not, try to change them. */
+ for (port = ntohs(rtp_exp->tuple.dst.u.udp.port);
+ port != 0; port += 2) {
+ rtp_exp->tuple.dst.u.udp.port = htons(port);
+ if (nf_ct_expect_related(rtp_exp) != 0)
+ continue;
+ rtcp_exp->tuple.dst.u.udp.port = htons(port + 1);
+ if (nf_ct_expect_related(rtcp_exp) == 0)
break;
+ nf_ct_unexpect_related(rtp_exp);
}
if (port == 0)
return NF_DROP;
if (!mangle_sdp(skb, ctinfo, ct, newip, port, dptr, datalen)) {
- nf_ct_unexpect_related(exp);
+ nf_ct_unexpect_related(rtp_exp);
+ nf_ct_unexpect_related(rtcp_exp);
return NF_DROP;
}
return NF_ACCEPT;
diff --git a/net/netfilter/nf_conntrack_sip.c b/net/netfilter/nf_conntrack_sip.c
index 813aa8c..217262e 100644
--- a/net/netfilter/nf_conntrack_sip.c
+++ b/net/netfilter/nf_conntrack_sip.c
@@ -63,7 +63,9 @@ EXPORT_SYMBOL_GPL(nf_nat_sip_expect_hook);
unsigned int (*nf_nat_sdp_hook)(struct sk_buff *skb,
const char **dptr,
unsigned int *datalen,
- struct nf_conntrack_expect *exp) __read_mostly;
+ struct nf_conntrack_expect *rtp_exp,
+ struct nf_conntrack_expect *rtcp_exp)
+ __read_mostly;
EXPORT_SYMBOL_GPL(nf_nat_sdp_hook);
static int string_len(const struct nf_conn *ct, const char *dptr,
@@ -659,18 +661,20 @@ static void flush_expectations(struct nf_conn *ct, bool media)
spin_unlock_bh(&nf_conntrack_lock);
}
-static int set_expected_rtp(struct sk_buff *skb,
- const char **dptr, unsigned int *datalen,
- union nf_inet_addr *daddr, __be16 port)
+static int set_expected_rtp_rtcp(struct sk_buff *skb,
+ const char **dptr, unsigned int *datalen,
+ union nf_inet_addr *daddr, __be16 port)
{
- struct nf_conntrack_expect *exp;
+ struct nf_conntrack_expect *exp, *rtp_exp, *rtcp_exp;
enum ip_conntrack_info ctinfo;
struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
union nf_inet_addr *saddr;
struct nf_conntrack_tuple tuple;
int family = ct->tuplehash[!dir].tuple.src.l3num;
- int skip_expect = 0, ret;
+ int skip_expect = 0, ret = NF_DROP;
+ u_int16_t base_port;
+ __be16 rtp_port, rtcp_port;
typeof(nf_nat_sdp_hook) nf_nat_sdp;
saddr = NULL;
@@ -704,23 +708,37 @@ static int set_expected_rtp(struct sk_buff *skb,
if (skip_expect)
return NF_ACCEPT;
- exp = nf_ct_expect_alloc(ct);
- if (exp == NULL)
- return NF_DROP;
- nf_ct_expect_init(exp, SIP_EXPECT_AUDIO, family, saddr, daddr,
- IPPROTO_UDP, NULL, &port);
+ base_port = ntohs(tuple.dst.u.udp.port) & ~1;
+ rtp_port = htons(base_port);
+ rtcp_port = htons(base_port + 1);
+
+ rtp_exp = nf_ct_expect_alloc(ct);
+ if (rtp_exp == NULL)
+ goto err1;
+ nf_ct_expect_init(rtp_exp, SIP_EXPECT_AUDIO, family, saddr, daddr,
+ IPPROTO_UDP, NULL, &rtp_port);
+
+ rtcp_exp = nf_ct_expect_alloc(ct);
+ if (rtcp_exp == NULL)
+ goto err2;
+ nf_ct_expect_init(rtcp_exp, SIP_EXPECT_AUDIO, family, saddr, daddr,
+ IPPROTO_UDP, NULL, &rtcp_port);
nf_nat_sdp = rcu_dereference(nf_nat_sdp_hook);
if (nf_nat_sdp && ct->status & IPS_NAT_MASK)
- ret = nf_nat_sdp(skb, dptr, datalen, exp);
+ ret = nf_nat_sdp(skb, dptr, datalen, rtp_exp, rtcp_exp);
else {
- if (nf_ct_expect_related(exp) != 0)
- ret = NF_DROP;
- else
- ret = NF_ACCEPT;
+ if (nf_ct_expect_related(rtp_exp) == 0) {
+ if (nf_ct_expect_related(rtcp_exp) != 0)
+ nf_ct_unexpect_related(rtp_exp);
+ else
+ ret = NF_ACCEPT;
+ }
}
- nf_ct_expect_put(exp);
-
+ nf_ct_expect_put(rtcp_exp);
+err2:
+ nf_ct_expect_put(rtp_exp);
+err1:
return ret;
}
@@ -758,7 +776,7 @@ static int process_sdp(struct sk_buff *skb,
if (port < 1024 || port > 65535)
return NF_DROP;
- return set_expected_rtp(skb, dptr, datalen, &addr, htons(port));
+ return set_expected_rtp_rtcp(skb, dptr, datalen, &addr, htons(port));
}
static int process_invite_response(struct sk_buff *skb,
const char **dptr, unsigned int *datalen,
@@ -1101,7 +1119,7 @@ static const struct nf_conntrack_expect_policy sip_exp_policy[SIP_EXPECT_MAX + 1
.timeout = 3 * 60,
},
[SIP_EXPECT_AUDIO] = {
- .max_expected = IP_CT_DIR_MAX,
+ .max_expected = 2 * IP_CT_DIR_MAX,
.timeout = 3 * 60,
},
};
^ permalink raw reply related [flat|nested] 39+ messages in thread* [NETFILTER 29/32]: nf_nat_sip: split up SDP mangling
2008-03-25 14:14 [METFILTER 00/32]: SIP helper update Patrick McHardy
` (27 preceding siblings ...)
2008-03-25 14:15 ` [NETFILTER 28/32]: nf_conntrack_sip: create RTCP expectations Patrick McHardy
@ 2008-03-25 14:15 ` Patrick McHardy
2008-03-25 14:15 ` [NETFILTER 30/32]: nf_conntrack_sip: support multiple media channels Patrick McHardy
` (3 subsequent siblings)
32 siblings, 0 replies; 39+ messages in thread
From: Patrick McHardy @ 2008-03-25 14:15 UTC (permalink / raw)
To: davem; +Cc: Patrick McHardy, netfilter-devel
[NETFILTER]: nf_nat_sip: split up SDP mangling
The SDP connection addresses may be contained in the payload multiple
times (in the session description and/or once per media description),
currently only the session description is properly updated. Split up
SDP mangling so the function setting up expectations only updates the
media port, update connection addresses from media descriptions while
parsing them and at the end update the session description when the
final addresses are known.
Signed-off-by: Patrick McHardy <kaber@trash.net>
---
commit 1f7d1e1804a04963595888f07e17453d2d5996f4
tree 8de0e5051019fd66f1ca956efd63b6465d4fae7d
parent bd085bafc458c50d639e3997fdff52fc457173ba
author Patrick McHardy <kaber@trash.net> Tue, 25 Mar 2008 12:45:22 +0100
committer Patrick McHardy <kaber@trash.net> Tue, 25 Mar 2008 14:09:59 +0100
include/linux/netfilter/nf_conntrack_sip.h | 25 ++++-
net/ipv4/netfilter/nf_nat_sip.c | 121 +++++++++++++++++-------
net/netfilter/nf_conntrack_sip.c | 142 +++++++++++++++++++++++-----
3 files changed, 219 insertions(+), 69 deletions(-)
diff --git a/include/linux/netfilter/nf_conntrack_sip.h b/include/linux/netfilter/nf_conntrack_sip.h
index 6ddf95f..eca3ad3 100644
--- a/include/linux/netfilter/nf_conntrack_sip.h
+++ b/include/linux/netfilter/nf_conntrack_sip.h
@@ -93,11 +93,26 @@ extern unsigned int (*nf_nat_sip_expect_hook)(struct sk_buff *skb,
struct nf_conntrack_expect *exp,
unsigned int matchoff,
unsigned int matchlen);
-extern unsigned int (*nf_nat_sdp_hook)(struct sk_buff *skb,
- const char **dptr,
- unsigned int *datalen,
- struct nf_conntrack_expect *rtp_exp,
- struct nf_conntrack_expect *rtcp_exp);
+extern unsigned int (*nf_nat_sdp_addr_hook)(struct sk_buff *skb,
+ const char **dptr,
+ unsigned int dataoff,
+ unsigned int *datalen,
+ enum sdp_header_types type,
+ enum sdp_header_types term,
+ const union nf_inet_addr *addr);
+extern unsigned int (*nf_nat_sdp_session_hook)(struct sk_buff *skb,
+ const char **dptr,
+ unsigned int dataoff,
+ unsigned int *datalen,
+ const union nf_inet_addr *addr);
+extern unsigned int (*nf_nat_sdp_media_hook)(struct sk_buff *skb,
+ const char **dptr,
+ unsigned int *datalen,
+ struct nf_conntrack_expect *rtp_exp,
+ struct nf_conntrack_expect *rtcp_exp,
+ unsigned int mediaoff,
+ unsigned int medialen,
+ union nf_inet_addr *rtp_addr);
extern int ct_sip_parse_request(const struct nf_conn *ct,
const char *dptr, unsigned int datalen,
diff --git a/net/ipv4/netfilter/nf_nat_sip.c b/net/ipv4/netfilter/nf_nat_sip.c
index f73ab48..4429069 100644
--- a/net/ipv4/netfilter/nf_nat_sip.c
+++ b/net/ipv4/netfilter/nf_nat_sip.c
@@ -316,45 +316,77 @@ static int mangle_content_len(struct sk_buff *skb,
buffer, buflen);
}
-static unsigned mangle_sdp_packet(struct sk_buff *skb,
- const char **dptr, unsigned int *datalen,
+static unsigned mangle_sdp_packet(struct sk_buff *skb, const char **dptr,
+ unsigned int dataoff, unsigned int *datalen,
enum sdp_header_types type,
+ enum sdp_header_types term,
char *buffer, int buflen)
{
enum ip_conntrack_info ctinfo;
struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
unsigned int matchlen, matchoff;
- if (ct_sip_get_sdp_header(ct, *dptr, 0, *datalen, type, SDP_HDR_UNSPEC,
+ if (ct_sip_get_sdp_header(ct, *dptr, dataoff, *datalen, type, term,
&matchoff, &matchlen) <= 0)
return 0;
return mangle_packet(skb, dptr, datalen, matchoff, matchlen,
buffer, buflen);
}
-static unsigned int mangle_sdp(struct sk_buff *skb,
- enum ip_conntrack_info ctinfo,
- struct nf_conn *ct,
- __be32 newip, u_int16_t port,
- const char **dptr, unsigned int *datalen)
+static unsigned int ip_nat_sdp_addr(struct sk_buff *skb, const char **dptr,
+ unsigned int dataoff,
+ unsigned int *datalen,
+ enum sdp_header_types type,
+ enum sdp_header_types term,
+ const union nf_inet_addr *addr)
{
char buffer[sizeof("nnn.nnn.nnn.nnn")];
- unsigned int bufflen;
+ unsigned int buflen;
- /* Mangle owner and contact info. */
- bufflen = sprintf(buffer, "%u.%u.%u.%u", NIPQUAD(newip));
- if (!mangle_sdp_packet(skb, dptr, datalen, SDP_HDR_OWNER_IP4,
- buffer, bufflen))
+ buflen = sprintf(buffer, NIPQUAD_FMT, NIPQUAD(addr->ip));
+ if (!mangle_sdp_packet(skb, dptr, dataoff, datalen, type, term,
+ buffer, buflen))
return 0;
- if (!mangle_sdp_packet(skb, dptr, datalen, SDP_HDR_CONNECTION_IP4,
- buffer, bufflen))
+ return mangle_content_len(skb, dptr, datalen);
+}
+
+static unsigned int ip_nat_sdp_port(struct sk_buff *skb,
+ const char **dptr,
+ unsigned int *datalen,
+ unsigned int matchoff,
+ unsigned int matchlen,
+ u_int16_t port)
+{
+ char buffer[sizeof("nnnnn")];
+ unsigned int buflen;
+
+ buflen = sprintf(buffer, "%u", port);
+ if (!mangle_packet(skb, dptr, datalen, matchoff, matchlen,
+ buffer, buflen))
return 0;
- /* Mangle media port. */
- bufflen = sprintf(buffer, "%u", port);
- if (!mangle_sdp_packet(skb, dptr, datalen, SDP_HDR_MEDIA,
- buffer, bufflen))
+ return mangle_content_len(skb, dptr, datalen);
+}
+
+static unsigned int ip_nat_sdp_session(struct sk_buff *skb, const char **dptr,
+ unsigned int dataoff,
+ unsigned int *datalen,
+ const union nf_inet_addr *addr)
+{
+ char buffer[sizeof("nnn.nnn.nnn.nnn")];
+ unsigned int buflen;
+
+ /* Mangle session description owner and contact addresses */
+ buflen = sprintf(buffer, "%u.%u.%u.%u", NIPQUAD(addr->ip));
+ if (!mangle_sdp_packet(skb, dptr, dataoff, datalen,
+ SDP_HDR_OWNER_IP4, SDP_HDR_MEDIA,
+ buffer, buflen))
+ return 0;
+
+ if (!mangle_sdp_packet(skb, dptr, dataoff, datalen,
+ SDP_HDR_CONNECTION_IP4, SDP_HDR_MEDIA,
+ buffer, buflen))
return 0;
return mangle_content_len(skb, dptr, datalen);
@@ -362,32 +394,35 @@ static unsigned int mangle_sdp(struct sk_buff *skb,
/* So, this packet has hit the connection tracking matching code.
Mangle it, and change the expectation to match the new version. */
-static unsigned int ip_nat_sdp(struct sk_buff *skb,
- const char **dptr, unsigned int *datalen,
- struct nf_conntrack_expect *rtp_exp,
- struct nf_conntrack_expect *rtcp_exp)
+static unsigned int ip_nat_sdp_media(struct sk_buff *skb,
+ const char **dptr,
+ unsigned int *datalen,
+ struct nf_conntrack_expect *rtp_exp,
+ struct nf_conntrack_expect *rtcp_exp,
+ unsigned int mediaoff,
+ unsigned int medialen,
+ union nf_inet_addr *rtp_addr)
{
enum ip_conntrack_info ctinfo;
struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
- __be32 newip;
u_int16_t port;
/* Connection will come from reply */
if (ct->tuplehash[dir].tuple.src.u3.ip ==
ct->tuplehash[!dir].tuple.dst.u3.ip)
- newip = rtp_exp->tuple.dst.u3.ip;
+ rtp_addr->ip = rtp_exp->tuple.dst.u3.ip;
else
- newip = ct->tuplehash[!dir].tuple.dst.u3.ip;
+ rtp_addr->ip = ct->tuplehash[!dir].tuple.dst.u3.ip;
rtp_exp->saved_ip = rtp_exp->tuple.dst.u3.ip;
- rtp_exp->tuple.dst.u3.ip = newip;
+ rtp_exp->tuple.dst.u3.ip = rtp_addr->ip;
rtp_exp->saved_proto.udp.port = rtp_exp->tuple.dst.u.udp.port;
rtp_exp->dir = !dir;
rtp_exp->expectfn = ip_nat_sip_expected;
rtcp_exp->saved_ip = rtcp_exp->tuple.dst.u3.ip;
- rtcp_exp->tuple.dst.u3.ip = newip;
+ rtcp_exp->tuple.dst.u3.ip = rtp_addr->ip;
rtcp_exp->saved_proto.udp.port = rtcp_exp->tuple.dst.u.udp.port;
rtcp_exp->dir = !dir;
rtcp_exp->expectfn = ip_nat_sip_expected;
@@ -405,21 +440,29 @@ static unsigned int ip_nat_sdp(struct sk_buff *skb,
}
if (port == 0)
- return NF_DROP;
+ goto err1;
+
+ /* Update media port. */
+ if (rtp_exp->tuple.dst.u.udp.port != rtp_exp->saved_proto.udp.port &&
+ !ip_nat_sdp_port(skb, dptr, datalen, mediaoff, medialen, port))
+ goto err2;
- if (!mangle_sdp(skb, ctinfo, ct, newip, port, dptr, datalen)) {
- nf_ct_unexpect_related(rtp_exp);
- nf_ct_unexpect_related(rtcp_exp);
- return NF_DROP;
- }
return NF_ACCEPT;
+
+err2:
+ nf_ct_unexpect_related(rtp_exp);
+ nf_ct_unexpect_related(rtcp_exp);
+err1:
+ return NF_DROP;
}
static void __exit nf_nat_sip_fini(void)
{
rcu_assign_pointer(nf_nat_sip_hook, NULL);
rcu_assign_pointer(nf_nat_sip_expect_hook, NULL);
- rcu_assign_pointer(nf_nat_sdp_hook, NULL);
+ rcu_assign_pointer(nf_nat_sdp_addr_hook, NULL);
+ rcu_assign_pointer(nf_nat_sdp_session_hook, NULL);
+ rcu_assign_pointer(nf_nat_sdp_media_hook, NULL);
synchronize_rcu();
}
@@ -427,10 +470,14 @@ static int __init nf_nat_sip_init(void)
{
BUG_ON(nf_nat_sip_hook != NULL);
BUG_ON(nf_nat_sip_expect_hook != NULL);
- BUG_ON(nf_nat_sdp_hook != NULL);
+ BUG_ON(nf_nat_sdp_addr_hook != NULL);
+ BUG_ON(nf_nat_sdp_session_hook != NULL);
+ BUG_ON(nf_nat_sdp_media_hook != NULL);
rcu_assign_pointer(nf_nat_sip_hook, ip_nat_sip);
rcu_assign_pointer(nf_nat_sip_expect_hook, ip_nat_sip_expect);
- rcu_assign_pointer(nf_nat_sdp_hook, ip_nat_sdp);
+ rcu_assign_pointer(nf_nat_sdp_addr_hook, ip_nat_sdp_addr);
+ rcu_assign_pointer(nf_nat_sdp_session_hook, ip_nat_sdp_session);
+ rcu_assign_pointer(nf_nat_sdp_media_hook, ip_nat_sdp_media);
return 0;
}
diff --git a/net/netfilter/nf_conntrack_sip.c b/net/netfilter/nf_conntrack_sip.c
index 217262e..f929add 100644
--- a/net/netfilter/nf_conntrack_sip.c
+++ b/net/netfilter/nf_conntrack_sip.c
@@ -60,13 +60,34 @@ unsigned int (*nf_nat_sip_expect_hook)(struct sk_buff *skb,
unsigned int matchlen) __read_mostly;
EXPORT_SYMBOL_GPL(nf_nat_sip_expect_hook);
-unsigned int (*nf_nat_sdp_hook)(struct sk_buff *skb,
- const char **dptr,
- unsigned int *datalen,
- struct nf_conntrack_expect *rtp_exp,
- struct nf_conntrack_expect *rtcp_exp)
- __read_mostly;
-EXPORT_SYMBOL_GPL(nf_nat_sdp_hook);
+unsigned int (*nf_nat_sdp_addr_hook)(struct sk_buff *skb,
+ const char **dptr,
+ unsigned int dataoff,
+ unsigned int *datalen,
+ enum sdp_header_types type,
+ enum sdp_header_types term,
+ const union nf_inet_addr *addr)
+ __read_mostly;
+EXPORT_SYMBOL_GPL(nf_nat_sdp_addr_hook);
+
+unsigned int (*nf_nat_sdp_session_hook)(struct sk_buff *skb,
+ const char **dptr,
+ unsigned int dataoff,
+ unsigned int *datalen,
+ const union nf_inet_addr *addr)
+ __read_mostly;
+EXPORT_SYMBOL_GPL(nf_nat_sdp_session_hook);
+
+unsigned int (*nf_nat_sdp_media_hook)(struct sk_buff *skb,
+ const char **dptr,
+ unsigned int *datalen,
+ struct nf_conntrack_expect *rtp_exp,
+ struct nf_conntrack_expect *rtcp_exp,
+ unsigned int mediaoff,
+ unsigned int medialen,
+ union nf_inet_addr *rtp_addr)
+ __read_mostly;
+EXPORT_SYMBOL_GPL(nf_nat_sdp_media_hook);
static int string_len(const struct nf_conn *ct, const char *dptr,
const char *limit, int *shift)
@@ -613,6 +634,26 @@ int ct_sip_get_sdp_header(const struct nf_conn *ct, const char *dptr,
}
EXPORT_SYMBOL_GPL(ct_sip_get_sdp_header);
+static int ct_sip_parse_sdp_addr(const struct nf_conn *ct, const char *dptr,
+ unsigned int dataoff, unsigned int datalen,
+ enum sdp_header_types type,
+ enum sdp_header_types term,
+ unsigned int *matchoff, unsigned int *matchlen,
+ union nf_inet_addr *addr)
+{
+ int ret;
+
+ ret = ct_sip_get_sdp_header(ct, dptr, dataoff, datalen, type, term,
+ matchoff, matchlen);
+ if (ret <= 0)
+ return ret;
+
+ if (!parse_addr(ct, dptr + *matchoff, NULL, addr,
+ dptr + *matchoff + *matchlen))
+ return -1;
+ return 1;
+}
+
static int refresh_signalling_expectation(struct nf_conn *ct,
union nf_inet_addr *addr,
__be16 port,
@@ -663,7 +704,8 @@ static void flush_expectations(struct nf_conn *ct, bool media)
static int set_expected_rtp_rtcp(struct sk_buff *skb,
const char **dptr, unsigned int *datalen,
- union nf_inet_addr *daddr, __be16 port)
+ union nf_inet_addr *daddr, __be16 port,
+ unsigned int mediaoff, unsigned int medialen)
{
struct nf_conntrack_expect *exp, *rtp_exp, *rtcp_exp;
enum ip_conntrack_info ctinfo;
@@ -675,7 +717,7 @@ static int set_expected_rtp_rtcp(struct sk_buff *skb,
int skip_expect = 0, ret = NF_DROP;
u_int16_t base_port;
__be16 rtp_port, rtcp_port;
- typeof(nf_nat_sdp_hook) nf_nat_sdp;
+ typeof(nf_nat_sdp_media_hook) nf_nat_sdp_media;
saddr = NULL;
if (sip_direct_media) {
@@ -724,9 +766,10 @@ static int set_expected_rtp_rtcp(struct sk_buff *skb,
nf_ct_expect_init(rtcp_exp, SIP_EXPECT_AUDIO, family, saddr, daddr,
IPPROTO_UDP, NULL, &rtcp_port);
- nf_nat_sdp = rcu_dereference(nf_nat_sdp_hook);
- if (nf_nat_sdp && ct->status & IPS_NAT_MASK)
- ret = nf_nat_sdp(skb, dptr, datalen, rtp_exp, rtcp_exp);
+ nf_nat_sdp_media = rcu_dereference(nf_nat_sdp_media_hook);
+ if (nf_nat_sdp_media && ct->status & IPS_NAT_MASK)
+ ret = nf_nat_sdp_media(skb, dptr, datalen, rtp_exp, rtcp_exp,
+ mediaoff, medialen, daddr);
else {
if (nf_ct_expect_related(rtp_exp) == 0) {
if (nf_ct_expect_related(rtcp_exp) != 0)
@@ -750,33 +793,78 @@ static int process_sdp(struct sk_buff *skb,
struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
int family = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.l3num;
unsigned int matchoff, matchlen;
- union nf_inet_addr addr;
+ unsigned int mediaoff, medialen;
+ unsigned int sdpoff;
+ unsigned int caddr_len, maddr_len;
+ union nf_inet_addr caddr, maddr, rtp_addr;
unsigned int port;
- enum sdp_header_types type;
+ enum sdp_header_types c_hdr;
+ int ret;
+ typeof(nf_nat_sdp_addr_hook) nf_nat_sdp_addr;
+ typeof(nf_nat_sdp_session_hook) nf_nat_sdp_session;
- /* Get address and port from SDP packet. */
- type = family == AF_INET ? SDP_HDR_CONNECTION_IP4 :
- SDP_HDR_CONNECTION_IP6;
+ c_hdr = family == AF_INET ? SDP_HDR_CONNECTION_IP4 :
+ SDP_HDR_CONNECTION_IP6;
+ /* Find beginning of session description */
if (ct_sip_get_sdp_header(ct, *dptr, 0, *datalen,
- type, SDP_HDR_UNSPEC,
+ SDP_HDR_VERSION, SDP_HDR_UNSPEC,
&matchoff, &matchlen) <= 0)
return NF_ACCEPT;
-
- /* We'll drop only if there are parse problems. */
- if (!parse_addr(ct, *dptr + matchoff, NULL, &addr, *dptr + *datalen))
- return NF_DROP;
-
- if (ct_sip_get_sdp_header(ct, *dptr, 0, *datalen,
+ sdpoff = matchoff;
+
+ /* The connection information is contained in the session description
+ * and/or once per media description. The first media description marks
+ * the end of the session description. */
+ caddr_len = 0;
+ if (ct_sip_parse_sdp_addr(ct, *dptr, sdpoff, *datalen,
+ c_hdr, SDP_HDR_MEDIA,
+ &matchoff, &matchlen, &caddr) > 0)
+ caddr_len = matchlen;
+
+ if (ct_sip_get_sdp_header(ct, *dptr, sdpoff, *datalen,
SDP_HDR_MEDIA, SDP_HDR_UNSPEC,
- &matchoff, &matchlen) <= 0)
+ &mediaoff, &medialen) <= 0)
return NF_ACCEPT;
- port = simple_strtoul(*dptr + matchoff, NULL, 10);
+ port = simple_strtoul(*dptr + mediaoff, NULL, 10);
if (port < 1024 || port > 65535)
return NF_DROP;
- return set_expected_rtp_rtcp(skb, dptr, datalen, &addr, htons(port));
+ /* The media description overrides the session description. */
+ maddr_len = 0;
+ if (ct_sip_parse_sdp_addr(ct, *dptr, mediaoff, *datalen,
+ c_hdr, SDP_HDR_MEDIA,
+ &matchoff, &matchlen, &maddr) > 0) {
+ maddr_len = matchlen;
+ memcpy(&rtp_addr, &maddr, sizeof(rtp_addr));
+ } else if (caddr_len)
+ memcpy(&rtp_addr, &caddr, sizeof(rtp_addr));
+ else
+ return NF_DROP;
+
+ ret = set_expected_rtp_rtcp(skb, dptr, datalen, &rtp_addr, htons(port),
+ mediaoff, medialen);
+ if (ret != NF_ACCEPT)
+ return ret;
+
+ /* Update media connection address if present */
+ if (maddr_len) {
+ nf_nat_sdp_addr = rcu_dereference(nf_nat_sdp_addr_hook);
+ if (nf_nat_sdp_addr && ct->status & IPS_NAT_MASK) {
+ ret = nf_nat_sdp_addr(skb, dptr, mediaoff, datalen,
+ c_hdr, SDP_HDR_MEDIA, &rtp_addr);
+ if (ret != NF_ACCEPT)
+ return ret;
+ }
+ }
+
+ /* Update session connection and owner addresses */
+ nf_nat_sdp_session = rcu_dereference(nf_nat_sdp_session_hook);
+ if (nf_nat_sdp_session && ct->status & IPS_NAT_MASK)
+ ret = nf_nat_sdp_session(skb, dptr, sdpoff, datalen, &rtp_addr);
+
+ return ret;
}
static int process_invite_response(struct sk_buff *skb,
const char **dptr, unsigned int *datalen,
^ permalink raw reply related [flat|nested] 39+ messages in thread* [NETFILTER 30/32]: nf_conntrack_sip: support multiple media channels
2008-03-25 14:14 [METFILTER 00/32]: SIP helper update Patrick McHardy
` (28 preceding siblings ...)
2008-03-25 14:15 ` [NETFILTER 29/32]: nf_nat_sip: split up SDP mangling Patrick McHardy
@ 2008-03-25 14:15 ` Patrick McHardy
2008-03-25 14:15 ` [NETFILTER 31/32]: nf_conntrack_sip: RTP routing optimization Patrick McHardy
` (2 subsequent siblings)
32 siblings, 0 replies; 39+ messages in thread
From: Patrick McHardy @ 2008-03-25 14:15 UTC (permalink / raw)
To: davem; +Cc: Patrick McHardy, netfilter-devel
[NETFILTER]: nf_conntrack_sip: support multiple media channels
Add support for multiple media channels and use it to create
expectations for video streams when present.
Signed-off-by: Patrick McHardy <kaber@trash.net>
---
commit 1c04320897b232a4b7dd89c123469f6c6de911ae
tree 74dd9d95ee604f0b907b138d2a1c214cf87a95e6
parent 1f7d1e1804a04963595888f07e17453d2d5996f4
author Patrick McHardy <kaber@trash.net> Tue, 25 Mar 2008 12:45:24 +0100
committer Patrick McHardy <kaber@trash.net> Tue, 25 Mar 2008 14:09:59 +0100
include/linux/netfilter/nf_conntrack_sip.h | 14 +++
include/net/netfilter/nf_conntrack.h | 2
net/netfilter/nf_conntrack_sip.c | 121 +++++++++++++++++++++-------
3 files changed, 105 insertions(+), 32 deletions(-)
diff --git a/include/linux/netfilter/nf_conntrack_sip.h b/include/linux/netfilter/nf_conntrack_sip.h
index eca3ad3..71fa3eb 100644
--- a/include/linux/netfilter/nf_conntrack_sip.h
+++ b/include/linux/netfilter/nf_conntrack_sip.h
@@ -12,10 +12,24 @@ struct nf_ct_sip_master {
enum sip_expectation_classes {
SIP_EXPECT_SIGNALLING,
SIP_EXPECT_AUDIO,
+ SIP_EXPECT_VIDEO,
__SIP_EXPECT_MAX
};
#define SIP_EXPECT_MAX (__SIP_EXPECT_MAX - 1)
+struct sdp_media_type {
+ const char *name;
+ unsigned int len;
+ enum sip_expectation_classes class;
+};
+
+#define SDP_MEDIA_TYPE(__name, __class) \
+{ \
+ .name = (__name), \
+ .len = sizeof(__name) - 1, \
+ .class = (__class), \
+}
+
struct sip_handler {
const char *method;
unsigned int len;
diff --git a/include/net/netfilter/nf_conntrack.h b/include/net/netfilter/nf_conntrack.h
index 4a4f870..a3567a7 100644
--- a/include/net/netfilter/nf_conntrack.h
+++ b/include/net/netfilter/nf_conntrack.h
@@ -78,7 +78,7 @@ do { \
struct nf_conntrack_helper;
/* Must be kept in sync with the classes defined by helpers */
-#define NF_CT_MAX_EXPECT_CLASSES 2
+#define NF_CT_MAX_EXPECT_CLASSES 3
/* nf_conn feature for connections that have a helper */
struct nf_conn_help {
diff --git a/net/netfilter/nf_conntrack_sip.c b/net/netfilter/nf_conntrack_sip.c
index f929add..f40a525 100644
--- a/net/netfilter/nf_conntrack_sip.c
+++ b/net/netfilter/nf_conntrack_sip.c
@@ -112,6 +112,21 @@ static int digits_len(const struct nf_conn *ct, const char *dptr,
return len;
}
+/* get media type + port length */
+static int media_len(const struct nf_conn *ct, const char *dptr,
+ const char *limit, int *shift)
+{
+ int len = string_len(ct, dptr, limit, shift);
+
+ dptr += len;
+ if (dptr >= limit || *dptr != ' ')
+ return 0;
+ len++;
+ dptr++;
+
+ return len + digits_len(ct, dptr, limit, shift);
+}
+
static int parse_addr(const struct nf_conn *ct, const char *cp,
const char **endp, union nf_inet_addr *addr,
const char *limit)
@@ -563,7 +578,7 @@ static const struct sip_header ct_sdp_hdrs[] = {
[SDP_HDR_CONNECTION_IP4] = SDP_HDR("c=", "IN IP4 ", epaddr_len),
[SDP_HDR_OWNER_IP6] = SDP_HDR("o=", "IN IP6 ", epaddr_len),
[SDP_HDR_CONNECTION_IP6] = SDP_HDR("c=", "IN IP6 ", epaddr_len),
- [SDP_HDR_MEDIA] = SDP_HDR("m=", "audio ", digits_len),
+ [SDP_HDR_MEDIA] = SDP_HDR("m=", NULL, media_len),
};
/* Linear string search within SDP header values */
@@ -705,6 +720,7 @@ static void flush_expectations(struct nf_conn *ct, bool media)
static int set_expected_rtp_rtcp(struct sk_buff *skb,
const char **dptr, unsigned int *datalen,
union nf_inet_addr *daddr, __be16 port,
+ enum sip_expectation_classes class,
unsigned int mediaoff, unsigned int medialen)
{
struct nf_conntrack_expect *exp, *rtp_exp, *rtcp_exp;
@@ -743,7 +759,7 @@ static int set_expected_rtp_rtcp(struct sk_buff *skb,
exp = __nf_ct_expect_find(&tuple);
if (exp && exp->master != ct &&
nfct_help(exp->master)->helper == nfct_help(ct)->helper &&
- exp->class == SIP_EXPECT_AUDIO)
+ exp->class == class)
skip_expect = 1;
rcu_read_unlock();
@@ -757,13 +773,13 @@ static int set_expected_rtp_rtcp(struct sk_buff *skb,
rtp_exp = nf_ct_expect_alloc(ct);
if (rtp_exp == NULL)
goto err1;
- nf_ct_expect_init(rtp_exp, SIP_EXPECT_AUDIO, family, saddr, daddr,
+ nf_ct_expect_init(rtp_exp, class, family, saddr, daddr,
IPPROTO_UDP, NULL, &rtp_port);
rtcp_exp = nf_ct_expect_alloc(ct);
if (rtcp_exp == NULL)
goto err2;
- nf_ct_expect_init(rtcp_exp, SIP_EXPECT_AUDIO, family, saddr, daddr,
+ nf_ct_expect_init(rtcp_exp, class, family, saddr, daddr,
IPPROTO_UDP, NULL, &rtcp_port);
nf_nat_sdp_media = rcu_dereference(nf_nat_sdp_media_hook);
@@ -785,6 +801,28 @@ err1:
return ret;
}
+static const struct sdp_media_type sdp_media_types[] = {
+ SDP_MEDIA_TYPE("audio ", SIP_EXPECT_AUDIO),
+ SDP_MEDIA_TYPE("video ", SIP_EXPECT_VIDEO),
+};
+
+static const struct sdp_media_type *sdp_media_type(const char *dptr,
+ unsigned int matchoff,
+ unsigned int matchlen)
+{
+ const struct sdp_media_type *t;
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(sdp_media_types); i++) {
+ t = &sdp_media_types[i];
+ if (matchlen < t->len ||
+ strncmp(dptr + matchoff, t->name, t->len))
+ continue;
+ return t;
+ }
+ return NULL;
+}
+
static int process_sdp(struct sk_buff *skb,
const char **dptr, unsigned int *datalen,
unsigned int cseq)
@@ -796,13 +834,16 @@ static int process_sdp(struct sk_buff *skb,
unsigned int mediaoff, medialen;
unsigned int sdpoff;
unsigned int caddr_len, maddr_len;
+ unsigned int i;
union nf_inet_addr caddr, maddr, rtp_addr;
unsigned int port;
enum sdp_header_types c_hdr;
- int ret;
+ const struct sdp_media_type *t;
+ int ret = NF_ACCEPT;
typeof(nf_nat_sdp_addr_hook) nf_nat_sdp_addr;
typeof(nf_nat_sdp_session_hook) nf_nat_sdp_session;
+ nf_nat_sdp_addr = rcu_dereference(nf_nat_sdp_addr_hook);
c_hdr = family == AF_INET ? SDP_HDR_CONNECTION_IP4 :
SDP_HDR_CONNECTION_IP6;
@@ -822,41 +863,55 @@ static int process_sdp(struct sk_buff *skb,
&matchoff, &matchlen, &caddr) > 0)
caddr_len = matchlen;
- if (ct_sip_get_sdp_header(ct, *dptr, sdpoff, *datalen,
- SDP_HDR_MEDIA, SDP_HDR_UNSPEC,
- &mediaoff, &medialen) <= 0)
- return NF_ACCEPT;
+ mediaoff = sdpoff;
+ for (i = 0; i < ARRAY_SIZE(sdp_media_types); ) {
+ if (ct_sip_get_sdp_header(ct, *dptr, mediaoff, *datalen,
+ SDP_HDR_MEDIA, SDP_HDR_UNSPEC,
+ &mediaoff, &medialen) <= 0)
+ break;
- port = simple_strtoul(*dptr + mediaoff, NULL, 10);
- if (port < 1024 || port > 65535)
- return NF_DROP;
+ /* Get media type and port number. A media port value of zero
+ * indicates an inactive stream. */
+ t = sdp_media_type(*dptr, mediaoff, medialen);
+ if (!t) {
+ mediaoff += medialen;
+ continue;
+ }
+ mediaoff += t->len;
+ medialen -= t->len;
- /* The media description overrides the session description. */
- maddr_len = 0;
- if (ct_sip_parse_sdp_addr(ct, *dptr, mediaoff, *datalen,
- c_hdr, SDP_HDR_MEDIA,
- &matchoff, &matchlen, &maddr) > 0) {
- maddr_len = matchlen;
- memcpy(&rtp_addr, &maddr, sizeof(rtp_addr));
- } else if (caddr_len)
- memcpy(&rtp_addr, &caddr, sizeof(rtp_addr));
- else
- return NF_DROP;
+ port = simple_strtoul(*dptr + mediaoff, NULL, 10);
+ if (port == 0)
+ continue;
+ if (port < 1024 || port > 65535)
+ return NF_DROP;
- ret = set_expected_rtp_rtcp(skb, dptr, datalen, &rtp_addr, htons(port),
- mediaoff, medialen);
- if (ret != NF_ACCEPT)
- return ret;
+ /* The media description overrides the session description. */
+ maddr_len = 0;
+ if (ct_sip_parse_sdp_addr(ct, *dptr, mediaoff, *datalen,
+ c_hdr, SDP_HDR_MEDIA,
+ &matchoff, &matchlen, &maddr) > 0) {
+ maddr_len = matchlen;
+ memcpy(&rtp_addr, &maddr, sizeof(rtp_addr));
+ } else if (caddr_len)
+ memcpy(&rtp_addr, &caddr, sizeof(rtp_addr));
+ else
+ return NF_DROP;
+
+ ret = set_expected_rtp_rtcp(skb, dptr, datalen,
+ &rtp_addr, htons(port), t->class,
+ mediaoff, medialen);
+ if (ret != NF_ACCEPT)
+ return ret;
- /* Update media connection address if present */
- if (maddr_len) {
- nf_nat_sdp_addr = rcu_dereference(nf_nat_sdp_addr_hook);
- if (nf_nat_sdp_addr && ct->status & IPS_NAT_MASK) {
+ /* Update media connection address if present */
+ if (maddr_len && nf_nat_sdp_addr && ct->status & IPS_NAT_MASK) {
ret = nf_nat_sdp_addr(skb, dptr, mediaoff, datalen,
c_hdr, SDP_HDR_MEDIA, &rtp_addr);
if (ret != NF_ACCEPT)
return ret;
}
+ i++;
}
/* Update session connection and owner addresses */
@@ -1210,6 +1265,10 @@ static const struct nf_conntrack_expect_policy sip_exp_policy[SIP_EXPECT_MAX + 1
.max_expected = 2 * IP_CT_DIR_MAX,
.timeout = 3 * 60,
},
+ [SIP_EXPECT_VIDEO] = {
+ .max_expected = 2 * IP_CT_DIR_MAX,
+ .timeout = 3 * 60,
+ },
};
static void nf_conntrack_sip_fini(void)
^ permalink raw reply related [flat|nested] 39+ messages in thread* [NETFILTER 31/32]: nf_conntrack_sip: RTP routing optimization
2008-03-25 14:14 [METFILTER 00/32]: SIP helper update Patrick McHardy
` (29 preceding siblings ...)
2008-03-25 14:15 ` [NETFILTER 30/32]: nf_conntrack_sip: support multiple media channels Patrick McHardy
@ 2008-03-25 14:15 ` Patrick McHardy
2008-03-25 14:15 ` [NETFILTER 32/32]: nf_conntrack_sip: update copyright Patrick McHardy
2008-03-26 3:29 ` [METFILTER 00/32]: SIP helper update David Miller
32 siblings, 0 replies; 39+ messages in thread
From: Patrick McHardy @ 2008-03-25 14:15 UTC (permalink / raw)
To: davem; +Cc: Patrick McHardy, netfilter-devel
[NETFILTER]: nf_conntrack_sip: RTP routing optimization
Optimize call routing between NATed endpoints: when an external
registrar sends a media description that contains an existing RTP
expectation from a different SNATed connection, the gatekeeper
is trying to route the call directly between the two endpoints.
We assume both endpoints can reach each other directly and
"un-NAT" the addresses, which makes the media stream go between
the two endpoints directly.
Signed-off-by: Patrick McHardy <kaber@trash.net>
---
commit 5b4954e2047534f6f4347597a68cb7f09a3389ea
tree 22ea8eda5dde1d76c2a11adc273c16691fcfdb90
parent 1c04320897b232a4b7dd89c123469f6c6de911ae
author Patrick McHardy <kaber@trash.net> Tue, 25 Mar 2008 12:45:25 +0100
committer Patrick McHardy <kaber@trash.net> Tue, 25 Mar 2008 14:09:59 +0100
include/linux/netfilter/nf_conntrack_sip.h | 6 +++
net/ipv4/netfilter/nf_nat_sip.c | 3 +
net/netfilter/nf_conntrack_sip.c | 59 +++++++++++++++++++++++-----
3 files changed, 58 insertions(+), 10 deletions(-)
diff --git a/include/linux/netfilter/nf_conntrack_sip.h b/include/linux/netfilter/nf_conntrack_sip.h
index 71fa3eb..5da04e5 100644
--- a/include/linux/netfilter/nf_conntrack_sip.h
+++ b/include/linux/netfilter/nf_conntrack_sip.h
@@ -114,6 +114,12 @@ extern unsigned int (*nf_nat_sdp_addr_hook)(struct sk_buff *skb,
enum sdp_header_types type,
enum sdp_header_types term,
const union nf_inet_addr *addr);
+extern unsigned int (*nf_nat_sdp_port_hook)(struct sk_buff *skb,
+ const char **dptr,
+ unsigned int *datalen,
+ unsigned int matchoff,
+ unsigned int matchlen,
+ u_int16_t port);
extern unsigned int (*nf_nat_sdp_session_hook)(struct sk_buff *skb,
const char **dptr,
unsigned int dataoff,
diff --git a/net/ipv4/netfilter/nf_nat_sip.c b/net/ipv4/netfilter/nf_nat_sip.c
index 4429069..bcddccd 100644
--- a/net/ipv4/netfilter/nf_nat_sip.c
+++ b/net/ipv4/netfilter/nf_nat_sip.c
@@ -461,6 +461,7 @@ static void __exit nf_nat_sip_fini(void)
rcu_assign_pointer(nf_nat_sip_hook, NULL);
rcu_assign_pointer(nf_nat_sip_expect_hook, NULL);
rcu_assign_pointer(nf_nat_sdp_addr_hook, NULL);
+ rcu_assign_pointer(nf_nat_sdp_port_hook, NULL);
rcu_assign_pointer(nf_nat_sdp_session_hook, NULL);
rcu_assign_pointer(nf_nat_sdp_media_hook, NULL);
synchronize_rcu();
@@ -471,11 +472,13 @@ static int __init nf_nat_sip_init(void)
BUG_ON(nf_nat_sip_hook != NULL);
BUG_ON(nf_nat_sip_expect_hook != NULL);
BUG_ON(nf_nat_sdp_addr_hook != NULL);
+ BUG_ON(nf_nat_sdp_port_hook != NULL);
BUG_ON(nf_nat_sdp_session_hook != NULL);
BUG_ON(nf_nat_sdp_media_hook != NULL);
rcu_assign_pointer(nf_nat_sip_hook, ip_nat_sip);
rcu_assign_pointer(nf_nat_sip_expect_hook, ip_nat_sip_expect);
rcu_assign_pointer(nf_nat_sdp_addr_hook, ip_nat_sdp_addr);
+ rcu_assign_pointer(nf_nat_sdp_port_hook, ip_nat_sdp_port);
rcu_assign_pointer(nf_nat_sdp_session_hook, ip_nat_sdp_session);
rcu_assign_pointer(nf_nat_sdp_media_hook, ip_nat_sdp_media);
return 0;
diff --git a/net/netfilter/nf_conntrack_sip.c b/net/netfilter/nf_conntrack_sip.c
index f40a525..57de22c 100644
--- a/net/netfilter/nf_conntrack_sip.c
+++ b/net/netfilter/nf_conntrack_sip.c
@@ -70,6 +70,14 @@ unsigned int (*nf_nat_sdp_addr_hook)(struct sk_buff *skb,
__read_mostly;
EXPORT_SYMBOL_GPL(nf_nat_sdp_addr_hook);
+unsigned int (*nf_nat_sdp_port_hook)(struct sk_buff *skb,
+ const char **dptr,
+ unsigned int *datalen,
+ unsigned int matchoff,
+ unsigned int matchlen,
+ u_int16_t port) __read_mostly;
+EXPORT_SYMBOL_GPL(nf_nat_sdp_port_hook);
+
unsigned int (*nf_nat_sdp_session_hook)(struct sk_buff *skb,
const char **dptr,
unsigned int dataoff,
@@ -730,9 +738,10 @@ static int set_expected_rtp_rtcp(struct sk_buff *skb,
union nf_inet_addr *saddr;
struct nf_conntrack_tuple tuple;
int family = ct->tuplehash[!dir].tuple.src.l3num;
- int skip_expect = 0, ret = NF_DROP;
+ int direct_rtp = 0, skip_expect = 0, ret = NF_DROP;
u_int16_t base_port;
__be16 rtp_port, rtcp_port;
+ typeof(nf_nat_sdp_port_hook) nf_nat_sdp_port;
typeof(nf_nat_sdp_media_hook) nf_nat_sdp_media;
saddr = NULL;
@@ -746,6 +755,14 @@ static int set_expected_rtp_rtcp(struct sk_buff *skb,
* to register it since we can see the same media description multiple
* times on different connections in case multiple endpoints receive
* the same call.
+ *
+ * RTP optimization: if we find a matching media channel expectation
+ * and both the expectation and this connection are SNATed, we assume
+ * both sides can reach each other directly and use the final
+ * destination address from the expectation. We still need to keep
+ * the NATed expectations for media that might arrive from the
+ * outside, and additionally need to expect the direct RTP stream
+ * in case it passes through us even without NAT.
*/
memset(&tuple, 0, sizeof(tuple));
if (saddr)
@@ -756,20 +773,42 @@ static int set_expected_rtp_rtcp(struct sk_buff *skb,
tuple.dst.u.udp.port = port;
rcu_read_lock();
- exp = __nf_ct_expect_find(&tuple);
- if (exp && exp->master != ct &&
- nfct_help(exp->master)->helper == nfct_help(ct)->helper &&
- exp->class == class)
- skip_expect = 1;
- rcu_read_unlock();
+ do {
+ exp = __nf_ct_expect_find(&tuple);
- if (skip_expect)
- return NF_ACCEPT;
+ if (!exp || exp->master == ct ||
+ nfct_help(exp->master)->helper != nfct_help(ct)->helper ||
+ exp->class != class)
+ break;
+
+ if (exp->tuple.src.l3num == AF_INET && !direct_rtp &&
+ (exp->saved_ip != exp->tuple.dst.u3.ip ||
+ exp->saved_proto.udp.port != exp->tuple.dst.u.udp.port) &&
+ ct->status & IPS_NAT_MASK) {
+ daddr->ip = exp->saved_ip;
+ tuple.dst.u3.ip = exp->saved_ip;
+ tuple.dst.u.udp.port = exp->saved_proto.udp.port;
+ direct_rtp = 1;
+ } else
+ skip_expect = 1;
+ } while (!skip_expect);
+ rcu_read_unlock();
base_port = ntohs(tuple.dst.u.udp.port) & ~1;
rtp_port = htons(base_port);
rtcp_port = htons(base_port + 1);
+ if (direct_rtp) {
+ nf_nat_sdp_port = rcu_dereference(nf_nat_sdp_port_hook);
+ if (nf_nat_sdp_port &&
+ !nf_nat_sdp_port(skb, dptr, datalen,
+ mediaoff, medialen, ntohs(rtp_port)))
+ goto err1;
+ }
+
+ if (skip_expect)
+ return NF_ACCEPT;
+
rtp_exp = nf_ct_expect_alloc(ct);
if (rtp_exp == NULL)
goto err1;
@@ -783,7 +822,7 @@ static int set_expected_rtp_rtcp(struct sk_buff *skb,
IPPROTO_UDP, NULL, &rtcp_port);
nf_nat_sdp_media = rcu_dereference(nf_nat_sdp_media_hook);
- if (nf_nat_sdp_media && ct->status & IPS_NAT_MASK)
+ if (nf_nat_sdp_media && ct->status & IPS_NAT_MASK && !direct_rtp)
ret = nf_nat_sdp_media(skb, dptr, datalen, rtp_exp, rtcp_exp,
mediaoff, medialen, daddr);
else {
^ permalink raw reply related [flat|nested] 39+ messages in thread* [NETFILTER 32/32]: nf_conntrack_sip: update copyright
2008-03-25 14:14 [METFILTER 00/32]: SIP helper update Patrick McHardy
` (30 preceding siblings ...)
2008-03-25 14:15 ` [NETFILTER 31/32]: nf_conntrack_sip: RTP routing optimization Patrick McHardy
@ 2008-03-25 14:15 ` Patrick McHardy
2008-03-26 3:29 ` [METFILTER 00/32]: SIP helper update David Miller
32 siblings, 0 replies; 39+ messages in thread
From: Patrick McHardy @ 2008-03-25 14:15 UTC (permalink / raw)
To: davem; +Cc: Patrick McHardy, netfilter-devel
[NETFILTER]: nf_conntrack_sip: update copyright
Signed-off-by: Patrick McHardy <kaber@trash.net>
---
commit 5ada5a1adfeb1f7fdad61d02add18a4e47750b30
tree c41e7b0d5568d855a6afecdd92d0c244478a6c94
parent 5b4954e2047534f6f4347597a68cb7f09a3389ea
author Patrick McHardy <kaber@trash.net> Tue, 25 Mar 2008 14:43:46 +0100
committer Patrick McHardy <kaber@trash.net> Tue, 25 Mar 2008 14:43:46 +0100
net/ipv4/netfilter/nf_nat_sip.c | 2 ++
net/netfilter/nf_conntrack_sip.c | 2 ++
2 files changed, 4 insertions(+), 0 deletions(-)
diff --git a/net/ipv4/netfilter/nf_nat_sip.c b/net/ipv4/netfilter/nf_nat_sip.c
index bcddccd..4334d5c 100644
--- a/net/ipv4/netfilter/nf_nat_sip.c
+++ b/net/ipv4/netfilter/nf_nat_sip.c
@@ -2,6 +2,8 @@
*
* (C) 2005 by Christian Hentschel <chentschel@arnet.com.ar>
* based on RR's ip_nat_ftp.c and other modules.
+ * (C) 2007 United Security Providers
+ * (C) 2007, 2008 Patrick McHardy <kaber@trash.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
diff --git a/net/netfilter/nf_conntrack_sip.c b/net/netfilter/nf_conntrack_sip.c
index 57de22c..da5dec6 100644
--- a/net/netfilter/nf_conntrack_sip.c
+++ b/net/netfilter/nf_conntrack_sip.c
@@ -2,6 +2,8 @@
*
* (C) 2005 by Christian Hentschel <chentschel@arnet.com.ar>
* based on RR's ip_conntrack_ftp.c and other modules.
+ * (C) 2007 United Security Providers
+ * (C) 2007, 2008 Patrick McHardy <kaber@trash.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
^ permalink raw reply related [flat|nested] 39+ messages in thread* Re: [METFILTER 00/32]: SIP helper update
2008-03-25 14:14 [METFILTER 00/32]: SIP helper update Patrick McHardy
` (31 preceding siblings ...)
2008-03-25 14:15 ` [NETFILTER 32/32]: nf_conntrack_sip: update copyright Patrick McHardy
@ 2008-03-26 3:29 ` David Miller
32 siblings, 0 replies; 39+ messages in thread
From: David Miller @ 2008-03-26 3:29 UTC (permalink / raw)
To: kaber; +Cc: netfilter-devel
From: Patrick McHardy <kaber@trash.net>
Date: Tue, 25 Mar 2008 15:14:50 +0100 (MET)
> these patches for 2.6.26 contain a large update for the SIP connection
> tracking helper, fixing a number of issues with the current helper and
> improving robustness. A rough overview of the patches follows, the
> details are in the individual changelog entries:
All applied and pushed out to net-2.6.26, thanks!
^ permalink raw reply [flat|nested] 39+ messages in thread