* [NETFILTER 01/17]: x_tables: remove some unnecessary casts
2006-05-29 22:34 [NETFILTER 00/17]: Netfilter update for 2.6.18 Patrick McHardy
@ 2006-05-29 22:34 ` Patrick McHardy
2006-05-29 22:34 ` [NETFILTER 02/17]: x_tables: add SCTP/DCCP support where missing Patrick McHardy
` (16 subsequent siblings)
17 siblings, 0 replies; 23+ messages in thread
From: Patrick McHardy @ 2006-05-29 22:34 UTC (permalink / raw)
To: davem; +Cc: netfilter-devel, Patrick McHardy
[NETFILTER]: x_tables: remove some unnecessary casts
Signed-off-by: Patrick McHardy <kaber@trash.net>
---
commit 36e1d2c1e439bf08da7406cc82b01e18062a437e
tree 5f5847fc5a8483e67ec30d09bb034535a0729db5
parent 8bf89c20914d1323c80602ba60405b2873a6ef60
author Patrick McHardy <kaber@trash.net> Tue, 30 May 2006 00:02:36 +0200
committer Patrick McHardy <kaber@trash.net> Tue, 30 May 2006 00:02:36 +0200
net/ipv4/netfilter/ipt_hashlimit.c | 2 +-
net/netfilter/xt_connmark.c | 2 +-
net/netfilter/xt_dccp.c | 3 +--
net/netfilter/xt_mark.c | 2 +-
net/netfilter/xt_sctp.c | 4 +---
net/netfilter/xt_string.c | 2 +-
6 files changed, 6 insertions(+), 9 deletions(-)
diff --git a/net/ipv4/netfilter/ipt_hashlimit.c b/net/ipv4/netfilter/ipt_hashlimit.c
index 7c6836c..b88adc7 100644
--- a/net/ipv4/netfilter/ipt_hashlimit.c
+++ b/net/ipv4/netfilter/ipt_hashlimit.c
@@ -561,7 +561,7 @@ static void
hashlimit_destroy(const struct xt_match *match, void *matchinfo,
unsigned int matchsize)
{
- struct ipt_hashlimit_info *r = (struct ipt_hashlimit_info *) matchinfo;
+ struct ipt_hashlimit_info *r = matchinfo;
htable_put(r->hinfo);
}
diff --git a/net/netfilter/xt_connmark.c b/net/netfilter/xt_connmark.c
index dc26a27..56324c8 100644
--- a/net/netfilter/xt_connmark.c
+++ b/net/netfilter/xt_connmark.c
@@ -58,7 +58,7 @@ checkentry(const char *tablename,
unsigned int matchsize,
unsigned int hook_mask)
{
- struct xt_connmark_info *cm = (struct xt_connmark_info *)matchinfo;
+ struct xt_connmark_info *cm = matchinfo;
if (cm->mark > 0xffffffff || cm->mask > 0xffffffff) {
printk(KERN_WARNING "connmark: only support 32bit mark\n");
diff --git a/net/netfilter/xt_dccp.c b/net/netfilter/xt_dccp.c
index dfb10b6..2e2f825 100644
--- a/net/netfilter/xt_dccp.c
+++ b/net/netfilter/xt_dccp.c
@@ -101,8 +101,7 @@ match(const struct sk_buff *skb,
unsigned int protoff,
int *hotdrop)
{
- const struct xt_dccp_info *info =
- (const struct xt_dccp_info *)matchinfo;
+ const struct xt_dccp_info *info = matchinfo;
struct dccp_hdr _dh, *dh;
if (offset)
diff --git a/net/netfilter/xt_mark.c b/net/netfilter/xt_mark.c
index 8b385a3..876bc57 100644
--- a/net/netfilter/xt_mark.c
+++ b/net/netfilter/xt_mark.c
@@ -42,7 +42,7 @@ checkentry(const char *tablename,
unsigned int matchsize,
unsigned int hook_mask)
{
- struct xt_mark_info *minfo = (struct xt_mark_info *) matchinfo;
+ const struct xt_mark_info *minfo = matchinfo;
if (minfo->mark > 0xffffffff || minfo->mask > 0xffffffff) {
printk(KERN_WARNING "mark: only supports 32bit mark\n");
diff --git a/net/netfilter/xt_sctp.c b/net/netfilter/xt_sctp.c
index 34bd872..b5110e5 100644
--- a/net/netfilter/xt_sctp.c
+++ b/net/netfilter/xt_sctp.c
@@ -129,11 +129,9 @@ match(const struct sk_buff *skb,
unsigned int protoff,
int *hotdrop)
{
- const struct xt_sctp_info *info;
+ const struct xt_sctp_info *info = matchinfo;
sctp_sctphdr_t _sh, *sh;
- info = (const struct xt_sctp_info *)matchinfo;
-
if (offset) {
duprintf("Dropping non-first fragment.. FIXME\n");
return 0;
diff --git a/net/netfilter/xt_string.c b/net/netfilter/xt_string.c
index 79d9ea6..0ebb6ac 100644
--- a/net/netfilter/xt_string.c
+++ b/net/netfilter/xt_string.c
@@ -30,8 +30,8 @@ static int match(const struct sk_buff *s
unsigned int protoff,
int *hotdrop)
{
+ const struct xt_string_info *conf = matchinfo;
struct ts_state state;
- struct xt_string_info *conf = (struct xt_string_info *) matchinfo;
memset(&state, 0, sizeof(struct ts_state));
^ permalink raw reply related [flat|nested] 23+ messages in thread* [NETFILTER 02/17]: x_tables: add SCTP/DCCP support where missing
2006-05-29 22:34 [NETFILTER 00/17]: Netfilter update for 2.6.18 Patrick McHardy
2006-05-29 22:34 ` [NETFILTER 01/17]: x_tables: remove some unnecessary casts Patrick McHardy
@ 2006-05-29 22:34 ` Patrick McHardy
2006-05-29 22:34 ` [NETFILTER 03/17]: x_tables: add quota match Patrick McHardy
` (15 subsequent siblings)
17 siblings, 0 replies; 23+ messages in thread
From: Patrick McHardy @ 2006-05-29 22:34 UTC (permalink / raw)
To: davem; +Cc: netfilter-devel, Patrick McHardy
[NETFILTER]: x_tables: add SCTP/DCCP support where missing
Signed-off-by: Patrick McHardy <kaber@trash.net>
---
commit d8913efd2c5ec04b2b0447394c8ecdff37abe3c5
tree 405fc65eb82832af883bd5de9be421b739588c15
parent 36e1d2c1e439bf08da7406cc82b01e18062a437e
author Patrick McHardy <kaber@trash.net> Tue, 30 May 2006 00:02:37 +0200
committer Patrick McHardy <kaber@trash.net> Tue, 30 May 2006 00:02:37 +0200
net/ipv4/netfilter/ipt_CLUSTERIP.c | 20 +++--------
net/ipv4/netfilter/ipt_hashlimit.c | 64 +++++++++---------------------------
net/netfilter/xt_multiport.c | 7 ++--
3 files changed, 26 insertions(+), 65 deletions(-)
diff --git a/net/ipv4/netfilter/ipt_CLUSTERIP.c b/net/ipv4/netfilter/ipt_CLUSTERIP.c
index aad9d28..dbc83c5 100644
--- a/net/ipv4/netfilter/ipt_CLUSTERIP.c
+++ b/net/ipv4/netfilter/ipt_CLUSTERIP.c
@@ -241,25 +241,17 @@ clusterip_hashfn(struct sk_buff *skb, st
struct iphdr *iph = skb->nh.iph;
unsigned long hashval;
u_int16_t sport, dport;
- struct tcphdr *th;
- struct udphdr *uh;
- struct icmphdr *ih;
+ u_int16_t *ports;
switch (iph->protocol) {
case IPPROTO_TCP:
- th = (void *)iph+iph->ihl*4;
- sport = ntohs(th->source);
- dport = ntohs(th->dest);
- break;
case IPPROTO_UDP:
- uh = (void *)iph+iph->ihl*4;
- sport = ntohs(uh->source);
- dport = ntohs(uh->dest);
- break;
+ case IPPROTO_SCTP:
+ case IPPROTO_DCCP:
case IPPROTO_ICMP:
- ih = (void *)iph+iph->ihl*4;
- sport = ntohs(ih->un.echo.id);
- dport = (ih->type<<8)|ih->code;
+ ports = (void *)iph+iph->ihl*4;
+ sport = ports[0];
+ dport = ports[1];
break;
default:
if (net_ratelimit()) {
diff --git a/net/ipv4/netfilter/ipt_hashlimit.c b/net/ipv4/netfilter/ipt_hashlimit.c
index b88adc7..85edfb7 100644
--- a/net/ipv4/netfilter/ipt_hashlimit.c
+++ b/net/ipv4/netfilter/ipt_hashlimit.c
@@ -28,9 +28,6 @@ #include <linux/random.h>
#include <linux/jhash.h>
#include <linux/slab.h>
#include <linux/vmalloc.h>
-#include <linux/tcp.h>
-#include <linux/udp.h>
-#include <linux/sctp.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/list.h>
@@ -381,49 +378,6 @@ static inline void rateinfo_recalc(struc
dh->rateinfo.credit = dh->rateinfo.credit_cap;
}
-static inline int get_ports(const struct sk_buff *skb, int offset,
- u16 ports[2])
-{
- union {
- struct tcphdr th;
- struct udphdr uh;
- sctp_sctphdr_t sctph;
- } hdr_u, *ptr_u;
-
- /* Must not be a fragment. */
- if (offset)
- return 1;
-
- /* Must be big enough to read ports (both UDP and TCP have
- them at the start). */
- ptr_u = skb_header_pointer(skb, skb->nh.iph->ihl*4, 8, &hdr_u);
- if (!ptr_u)
- return 1;
-
- switch (skb->nh.iph->protocol) {
- case IPPROTO_TCP:
- ports[0] = ptr_u->th.source;
- ports[1] = ptr_u->th.dest;
- break;
- case IPPROTO_UDP:
- ports[0] = ptr_u->uh.source;
- ports[1] = ptr_u->uh.dest;
- break;
- case IPPROTO_SCTP:
- ports[0] = ptr_u->sctph.source;
- ports[1] = ptr_u->sctph.dest;
- break;
- default:
- /* all other protocols don't supprot per-port hash
- * buckets */
- ports[0] = ports[1] = 0;
- break;
- }
-
- return 0;
-}
-
-
static int
hashlimit_match(const struct sk_buff *skb,
const struct net_device *in,
@@ -449,8 +403,22 @@ hashlimit_match(const struct sk_buff *sk
dst.src_ip = skb->nh.iph->saddr;
if (hinfo->cfg.mode & IPT_HASHLIMIT_HASH_DPT
||hinfo->cfg.mode & IPT_HASHLIMIT_HASH_SPT) {
- u_int16_t ports[2];
- if (get_ports(skb, offset, ports)) {
+ u_int16_t _ports[2], *ports;
+
+ switch (skb->nh.iph->protocol) {
+ case IPPROTO_TCP:
+ case IPPROTO_UDP:
+ case IPPROTO_SCTP:
+ case IPPROTO_DCCP:
+ ports = skb_header_pointer(skb, skb->nh.iph->ihl*4,
+ sizeof(_ports), &_ports);
+ break;
+ default:
+ _ports[0] = _ports[1] = 0;
+ ports = _ports;
+ break;
+ }
+ if (!ports) {
/* We've been asked to examine this packet, and we
can't. Hence, no choice but to drop. */
*hotdrop = 1;
diff --git a/net/netfilter/xt_multiport.c b/net/netfilter/xt_multiport.c
index b56cd2b..1ff0a25 100644
--- a/net/netfilter/xt_multiport.c
+++ b/net/netfilter/xt_multiport.c
@@ -1,4 +1,4 @@
-/* Kernel module to match one of a list of TCP/UDP ports: ports are in
+/* Kernel module to match one of a list of TCP/UDP/SCTP/DCCP ports: ports are in
the same place so we can treat them as equal. */
/* (C) 1999-2001 Paul `Rusty' Russell
@@ -160,8 +160,9 @@ check(u_int16_t proto,
u_int8_t match_flags,
u_int8_t count)
{
- /* Must specify proto == TCP/UDP, no unknown flags or bad count */
- return (proto == IPPROTO_TCP || proto == IPPROTO_UDP)
+ /* Must specify supported protocol, no unknown flags or bad count */
+ return (proto == IPPROTO_TCP || proto == IPPROTO_UDP
+ || proto == IPPROTO_SCTP || proto == IPPROTO_DCCP)
&& !(ip_invflags & XT_INV_PROTO)
&& (match_flags == XT_MULTIPORT_SOURCE
|| match_flags == XT_MULTIPORT_DESTINATION
^ permalink raw reply related [flat|nested] 23+ messages in thread* [NETFILTER 03/17]: x_tables: add quota match
2006-05-29 22:34 [NETFILTER 00/17]: Netfilter update for 2.6.18 Patrick McHardy
2006-05-29 22:34 ` [NETFILTER 01/17]: x_tables: remove some unnecessary casts Patrick McHardy
2006-05-29 22:34 ` [NETFILTER 02/17]: x_tables: add SCTP/DCCP support where missing Patrick McHardy
@ 2006-05-29 22:34 ` Patrick McHardy
2006-05-29 22:34 ` [NETFILTER 04/17]: x_tables: add statistic match Patrick McHardy
` (14 subsequent siblings)
17 siblings, 0 replies; 23+ messages in thread
From: Patrick McHardy @ 2006-05-29 22:34 UTC (permalink / raw)
To: davem; +Cc: netfilter-devel, Patrick McHardy
[NETFILTER]: x_tables: add quota match
Signed-off-by: Patrick McHardy <kaber@trash.net>
---
commit 659702e42d110153954d98e895bdc2236e3d9b98
tree 76dad540e9d720968d4072df155e78f6175b85e6
parent d8913efd2c5ec04b2b0447394c8ecdff37abe3c5
author Patrick McHardy <kaber@trash.net> Tue, 30 May 2006 00:02:39 +0200
committer Patrick McHardy <kaber@trash.net> Tue, 30 May 2006 00:02:39 +0200
include/linux/netfilter/xt_quota.h | 16 ++++++
net/netfilter/Kconfig | 10 ++++
net/netfilter/Makefile | 1
net/netfilter/xt_quota.c | 96 ++++++++++++++++++++++++++++++++++++
4 files changed, 123 insertions(+), 0 deletions(-)
diff --git a/include/linux/netfilter/xt_quota.h b/include/linux/netfilter/xt_quota.h
new file mode 100644
index 0000000..acd7fd7
--- /dev/null
+++ b/include/linux/netfilter/xt_quota.h
@@ -0,0 +1,16 @@
+#ifndef _XT_QUOTA_H
+#define _XT_QUOTA_H
+
+enum xt_quota_flags {
+ XT_QUOTA_INVERT = 0x1,
+};
+#define XT_QUOTA_MASK 0x1
+
+struct xt_quota_info {
+ u_int32_t flags;
+ u_int32_t pad;
+ aligned_u64 quota;
+ struct xt_quota_info *master;
+};
+
+#endif /* _XT_QUOTA_H */
diff --git a/net/netfilter/Kconfig b/net/netfilter/Kconfig
index e2893ef..5543c7b 100644
--- a/net/netfilter/Kconfig
+++ b/net/netfilter/Kconfig
@@ -329,6 +329,16 @@ config NETFILTER_XT_MATCH_PKTTYPE
To compile it as a module, choose M here. If unsure, say N.
+config NETFILTER_XT_MATCH_QUOTA
+ tristate '"quota" match support'
+ depends on NETFILTER_XTABLES
+ help
+ This option adds a `quota' match, which allows to match on a
+ byte counter.
+
+ If you want to compile it as a module, say M here and read
+ <file:Documentation/modules.txt>. If unsure, say `N'.
+
config NETFILTER_XT_MATCH_REALM
tristate '"realm" match support'
depends on NETFILTER_XTABLES
diff --git a/net/netfilter/Makefile b/net/netfilter/Makefile
index 95b7e41..4b6a6ea 100644
--- a/net/netfilter/Makefile
+++ b/net/netfilter/Makefile
@@ -44,6 +44,7 @@ obj-$(CONFIG_NETFILTER_XT_MATCH_MARK) +=
obj-$(CONFIG_NETFILTER_XT_MATCH_MULTIPORT) += xt_multiport.o
obj-$(CONFIG_NETFILTER_XT_MATCH_POLICY) += xt_policy.o
obj-$(CONFIG_NETFILTER_XT_MATCH_PKTTYPE) += xt_pkttype.o
+obj-$(CONFIG_NETFILTER_XT_MATCH_QUOTA) += xt_quota.o
obj-$(CONFIG_NETFILTER_XT_MATCH_REALM) += xt_realm.o
obj-$(CONFIG_NETFILTER_XT_MATCH_SCTP) += xt_sctp.o
obj-$(CONFIG_NETFILTER_XT_MATCH_STATE) += xt_state.o
diff --git a/net/netfilter/xt_quota.c b/net/netfilter/xt_quota.c
new file mode 100644
index 0000000..4cdba74
--- /dev/null
+++ b/net/netfilter/xt_quota.c
@@ -0,0 +1,96 @@
+/*
+ * netfilter module to enforce network quotas
+ *
+ * Sam Johnston <samj@samj.net>
+ */
+#include <linux/skbuff.h>
+#include <linux/spinlock.h>
+
+#include <linux/netfilter/x_tables.h>
+#include <linux/netfilter/xt_quota.h>
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Sam Johnston <samj@samj.net>");
+
+static DEFINE_SPINLOCK(quota_lock);
+
+static int
+match(const struct sk_buff *skb,
+ const struct net_device *in, const struct net_device *out,
+ const struct xt_match *match, const void *matchinfo,
+ int offset, unsigned int protoff, int *hotdrop)
+{
+ struct xt_quota_info *q = ((struct xt_quota_info *)matchinfo)->master;
+ int ret = q->flags & XT_QUOTA_INVERT ? 1 : 0;
+
+ spin_lock_bh("a_lock);
+ if (q->quota >= skb->len) {
+ q->quota -= skb->len;
+ ret ^= 1;
+ } else {
+ /* we do not allow even small packets from now on */
+ q->quota = 0;
+ }
+ spin_unlock_bh("a_lock);
+
+ return ret;
+}
+
+static int
+checkentry(const char *tablename, const void *entry,
+ const struct xt_match *match, void *matchinfo,
+ unsigned int matchsize, unsigned int hook_mask)
+{
+ struct xt_quota_info *q = (struct xt_quota_info *)matchinfo;
+
+ if (q->flags & ~XT_QUOTA_MASK)
+ return 0;
+ /* For SMP, we only want to use one set of counters. */
+ q->master = q;
+ return 1;
+}
+
+static struct xt_match quota_match = {
+ .name = "quota",
+ .family = AF_INET,
+ .match = match,
+ .matchsize = sizeof(struct xt_quota_info),
+ .checkentry = checkentry,
+ .me = THIS_MODULE
+};
+
+static struct xt_match quota_match6 = {
+ .name = "quota",
+ .family = AF_INET6,
+ .match = match,
+ .matchsize = sizeof(struct xt_quota_info),
+ .checkentry = checkentry,
+ .me = THIS_MODULE
+};
+
+static int __init xt_quota_init(void)
+{
+ int ret;
+
+ ret = xt_register_match("a_match);
+ if (ret)
+ goto err1;
+ ret = xt_register_match("a_match6);
+ if (ret)
+ goto err2;
+ return ret;
+
+err2:
+ xt_unregister_match("a_match);
+err1:
+ return ret;
+}
+
+static void __exit xt_quota_fini(void)
+{
+ xt_unregister_match("a_match6);
+ xt_unregister_match("a_match);
+}
+
+module_init(xt_quota_init);
+module_exit(xt_quota_fini);
^ permalink raw reply related [flat|nested] 23+ messages in thread* [NETFILTER 04/17]: x_tables: add statistic match
2006-05-29 22:34 [NETFILTER 00/17]: Netfilter update for 2.6.18 Patrick McHardy
` (2 preceding siblings ...)
2006-05-29 22:34 ` [NETFILTER 03/17]: x_tables: add quota match Patrick McHardy
@ 2006-05-29 22:34 ` Patrick McHardy
2006-05-29 22:34 ` [NETFILTER 05/17]: recent match: replace by rewritten version Patrick McHardy
` (13 subsequent siblings)
17 siblings, 0 replies; 23+ messages in thread
From: Patrick McHardy @ 2006-05-29 22:34 UTC (permalink / raw)
To: davem; +Cc: netfilter-devel, Patrick McHardy
[NETFILTER]: x_tables: add statistic match
Add statistic match which is a combination of the nth and random matches.
Signed-off-by: Patrick McHardy <kaber@trash.net>
---
commit 3c167b1cf18ce1e39aa9ae2a519f4689b183f3ac
tree eeccf3380dc1d42cc4dd17d0099e1a3d9793ebd7
parent 659702e42d110153954d98e895bdc2236e3d9b98
author Patrick McHardy <kaber@trash.net> Tue, 30 May 2006 00:02:40 +0200
committer Patrick McHardy <kaber@trash.net> Tue, 30 May 2006 00:02:40 +0200
include/linux/netfilter/xt_statistic.h | 32 +++++++++
net/netfilter/Kconfig | 6 ++
net/netfilter/Makefile | 1
net/netfilter/xt_statistic.c | 112 ++++++++++++++++++++++++++++++++
4 files changed, 151 insertions(+), 0 deletions(-)
diff --git a/include/linux/netfilter/xt_statistic.h b/include/linux/netfilter/xt_statistic.h
new file mode 100644
index 0000000..c344e99
--- /dev/null
+++ b/include/linux/netfilter/xt_statistic.h
@@ -0,0 +1,32 @@
+#ifndef _XT_STATISTIC_H
+#define _XT_STATISTIC_H
+
+enum xt_statistic_mode {
+ XT_STATISTIC_MODE_RANDOM,
+ XT_STATISTIC_MODE_NTH,
+ __XT_STATISTIC_MODE_MAX
+};
+#define XT_STATISTIC_MODE_MAX (__XT_STATISTIC_MODE_MAX - 1)
+
+enum xt_statistic_flags {
+ XT_STATISTIC_INVERT = 0x1,
+};
+#define XT_STATISTIC_MASK 0x1
+
+struct xt_statistic_info {
+ u_int16_t mode;
+ u_int16_t flags;
+ union {
+ struct {
+ u_int32_t probability;
+ } random;
+ struct {
+ u_int32_t every;
+ u_int32_t packet;
+ u_int32_t count;
+ } nth;
+ } u;
+ struct xt_statistic_info *master __attribute__((aligned(8)));
+};
+
+#endif /* _XT_STATISTIC_H */
diff --git a/net/netfilter/Kconfig b/net/netfilter/Kconfig
index 5543c7b..85a7e17 100644
--- a/net/netfilter/Kconfig
+++ b/net/netfilter/Kconfig
@@ -375,6 +375,12 @@ config NETFILTER_XT_MATCH_STATE
To compile it as a module, choose M here. If unsure, say N.
+config NETFILTER_XT_MATCH_STATISTIC
+ tristate '"statistic" match support'
+ depends on NETFILTER_XTABLES
+ help
+ statistic module
+
config NETFILTER_XT_MATCH_STRING
tristate '"string" match support'
depends on NETFILTER_XTABLES
diff --git a/net/netfilter/Makefile b/net/netfilter/Makefile
index 4b6a6ea..df1da25 100644
--- a/net/netfilter/Makefile
+++ b/net/netfilter/Makefile
@@ -48,6 +48,7 @@ obj-$(CONFIG_NETFILTER_XT_MATCH_QUOTA) +
obj-$(CONFIG_NETFILTER_XT_MATCH_REALM) += xt_realm.o
obj-$(CONFIG_NETFILTER_XT_MATCH_SCTP) += xt_sctp.o
obj-$(CONFIG_NETFILTER_XT_MATCH_STATE) += xt_state.o
+obj-$(CONFIG_NETFILTER_XT_MATCH_STATISTIC) += xt_statistic.o
obj-$(CONFIG_NETFILTER_XT_MATCH_STRING) += xt_string.o
obj-$(CONFIG_NETFILTER_XT_MATCH_TCPMSS) += xt_tcpmss.o
obj-$(CONFIG_NETFILTER_XT_MATCH_PHYSDEV) += xt_physdev.o
diff --git a/net/netfilter/xt_statistic.c b/net/netfilter/xt_statistic.c
new file mode 100644
index 0000000..de1037f
--- /dev/null
+++ b/net/netfilter/xt_statistic.c
@@ -0,0 +1,112 @@
+/*
+ * Copyright (c) 2006 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
+ * published by the Free Software Foundation.
+ *
+ * Based on ipt_random and ipt_nth by Fabrice MARIE <fabrice@netfilter.org>.
+ */
+
+#include <linux/init.h>
+#include <linux/spinlock.h>
+#include <linux/skbuff.h>
+#include <linux/net.h>
+
+#include <linux/netfilter/xt_statistic.h>
+#include <linux/netfilter/x_tables.h>
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>");
+MODULE_DESCRIPTION("xtables statistical match module");
+MODULE_ALIAS("ipt_statistic");
+MODULE_ALIAS("ip6t_statistic");
+
+static DEFINE_SPINLOCK(nth_lock);
+
+static int
+match(const struct sk_buff *skb,
+ const struct net_device *in, const struct net_device *out,
+ const struct xt_match *match, const void *matchinfo,
+ int offset, unsigned int protoff, int *hotdrop)
+{
+ struct xt_statistic_info *info = (struct xt_statistic_info *)matchinfo;
+ int ret = info->flags & XT_STATISTIC_INVERT ? 1 : 0;
+
+ switch (info->mode) {
+ case XT_STATISTIC_MODE_RANDOM:
+ if ((net_random() & 0x7FFFFFFF) < info->u.random.probability)
+ ret ^= 1;
+ break;
+ case XT_STATISTIC_MODE_NTH:
+ info = info->master;
+ spin_lock_bh(&nth_lock);
+ if (info->u.nth.count++ == info->u.nth.every) {
+ info->u.nth.count = 0;
+ ret ^= 1;
+ }
+ spin_unlock_bh(&nth_lock);
+ break;
+ }
+
+ return ret;
+}
+
+static int
+checkentry(const char *tablename, const void *entry,
+ const struct xt_match *match, void *matchinfo,
+ unsigned int matchsize, unsigned int hook_mask)
+{
+ struct xt_statistic_info *info = (struct xt_statistic_info *)matchinfo;
+
+ if (info->mode > XT_STATISTIC_MODE_MAX ||
+ info->flags & ~XT_STATISTIC_MASK)
+ return 0;
+ info->master = info;
+ return 1;
+}
+
+static struct xt_match statistic_match = {
+ .name = "statistic",
+ .match = match,
+ .matchsize = sizeof(struct xt_statistic_info),
+ .checkentry = checkentry,
+ .family = AF_INET,
+ .me = THIS_MODULE,
+};
+
+static struct xt_match statistic_match6 = {
+ .name = "statistic",
+ .match = match,
+ .matchsize = sizeof(struct xt_statistic_info),
+ .checkentry = checkentry,
+ .family = AF_INET6,
+ .me = THIS_MODULE,
+};
+
+static int __init xt_statistic_init(void)
+{
+ int ret;
+
+ ret = xt_register_match(&statistic_match);
+ if (ret)
+ goto err1;
+
+ ret = xt_register_match(&statistic_match6);
+ if (ret)
+ goto err2;
+ return ret;
+err2:
+ xt_unregister_match(&statistic_match);
+err1:
+ return ret;
+}
+
+static void __exit xt_statistic_fini(void)
+{
+ xt_unregister_match(&statistic_match6);
+ xt_unregister_match(&statistic_match);
+}
+
+module_init(xt_statistic_init);
+module_exit(xt_statistic_fini);
^ permalink raw reply related [flat|nested] 23+ messages in thread* [NETFILTER 05/17]: recent match: replace by rewritten version
2006-05-29 22:34 [NETFILTER 00/17]: Netfilter update for 2.6.18 Patrick McHardy
` (3 preceding siblings ...)
2006-05-29 22:34 ` [NETFILTER 04/17]: x_tables: add statistic match Patrick McHardy
@ 2006-05-29 22:34 ` Patrick McHardy
2006-05-30 13:11 ` Stephen Frost
2006-05-29 22:34 ` [NETFILTER 06/17]: conntrack: don't call helpers for related ICMP messages Patrick McHardy
` (12 subsequent siblings)
17 siblings, 1 reply; 23+ messages in thread
From: Patrick McHardy @ 2006-05-29 22:34 UTC (permalink / raw)
To: davem; +Cc: netfilter-devel, Patrick McHardy
[NETFILTER]: recent match: replace by rewritten version
Replace the unmaintainable ipt_recent match by a rewritten version that
should be fully compatible.
Signed-off-by: Patrick McHardy <kaber@trash.net>
---
commit ac0eb5fe3ab7b4637f208b8dc79a5446e4d59dea
tree acf442e2e77727272fc1ca5c1f786340ebfc0b08
parent 3c167b1cf18ce1e39aa9ae2a519f4689b183f3ac
author Patrick McHardy <kaber@trash.net> Tue, 30 May 2006 00:02:41 +0200
committer Patrick McHardy <kaber@trash.net> Tue, 30 May 2006 00:02:41 +0200
net/ipv4/netfilter/ipt_recent.c | 1268 ++++++++++++---------------------------
1 files changed, 377 insertions(+), 891 deletions(-)
diff --git a/net/ipv4/netfilter/ipt_recent.c b/net/ipv4/netfilter/ipt_recent.c
index b847ee4..9686c4d 100644
--- a/net/ipv4/netfilter/ipt_recent.c
+++ b/net/ipv4/netfilter/ipt_recent.c
@@ -1,1007 +1,493 @@
-/* Kernel module to check if the source address has been seen recently. */
-/* Copyright 2002-2003, Stephen Frost, 2.5.x port by laforge@netfilter.org */
-/* Author: Stephen Frost <sfrost@snowman.net> */
-/* Project Page: http://snowman.net/projects/ipt_recent/ */
-/* This software is distributed under the terms of the GPL, Version 2 */
-/* This copyright does not cover user programs that use kernel services
- * by normal system calls. */
-
-#include <linux/module.h>
-#include <linux/skbuff.h>
+/*
+ * Copyright (c) 2006 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
+ * published by the Free Software Foundation.
+ *
+ * This is a replacement of the old ipt_recent module, which carried the
+ * following copyright notice:
+ *
+ * Author: Stephen Frost <sfrost@snowman.net>
+ * Copyright 2002-2003, Stephen Frost, 2.5.x port by laforge@netfilter.org
+ */
+#include <linux/init.h>
+#include <linux/moduleparam.h>
#include <linux/proc_fs.h>
-#include <linux/spinlock.h>
-#include <linux/interrupt.h>
-#include <asm/uaccess.h>
+#include <linux/seq_file.h>
+#include <linux/string.h>
#include <linux/ctype.h>
-#include <linux/ip.h>
-#include <linux/vmalloc.h>
-#include <linux/moduleparam.h>
+#include <linux/list.h>
+#include <linux/random.h>
+#include <linux/jhash.h>
+#include <linux/bitops.h>
+#include <linux/skbuff.h>
+#include <linux/inet.h>
#include <linux/netfilter_ipv4/ip_tables.h>
#include <linux/netfilter_ipv4/ipt_recent.h>
-#undef DEBUG
-#define HASH_LOG 9
+MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>");
+MODULE_DESCRIPTION("IP tables recently seen matching module");
+MODULE_LICENSE("GPL");
-/* Defaults, these can be overridden on the module command-line. */
static unsigned int ip_list_tot = 100;
static unsigned int ip_pkt_list_tot = 20;
static unsigned int ip_list_hash_size = 0;
static unsigned int ip_list_perms = 0644;
-#ifdef DEBUG
-static int debug = 1;
-#endif
-
-static char version[] =
-KERN_INFO RECENT_NAME " " RECENT_VER ": Stephen Frost <sfrost@snowman.net>. http://snowman.net/projects/ipt_recent/\n";
-
-MODULE_AUTHOR("Stephen Frost <sfrost@snowman.net>");
-MODULE_DESCRIPTION("IP tables recently seen matching module " RECENT_VER);
-MODULE_LICENSE("GPL");
module_param(ip_list_tot, uint, 0400);
module_param(ip_pkt_list_tot, uint, 0400);
module_param(ip_list_hash_size, uint, 0400);
module_param(ip_list_perms, uint, 0400);
-#ifdef DEBUG
-module_param(debug, bool, 0600);
-MODULE_PARM_DESC(debug,"enable debugging output");
-#endif
-MODULE_PARM_DESC(ip_list_tot,"number of IPs to remember per list");
-MODULE_PARM_DESC(ip_pkt_list_tot,"number of packets per IP to remember");
-MODULE_PARM_DESC(ip_list_hash_size,"size of hash table used to look up IPs");
-MODULE_PARM_DESC(ip_list_perms,"permissions on /proc/net/ipt_recent/* files");
-
-/* Structure of our list of recently seen addresses. */
-struct recent_ip_list {
- u_int32_t addr;
- u_int8_t ttl;
- unsigned long last_seen;
- unsigned long *last_pkts;
- u_int32_t oldest_pkt;
- u_int32_t hash_entry;
- u_int32_t time_pos;
-};
-
-struct time_info_list {
- u_int32_t position;
- u_int32_t time;
+MODULE_PARM_DESC(ip_list_tot, "number of IPs to remember per list");
+MODULE_PARM_DESC(ip_pkt_list_tot, "number of packets per IP to remember (max. 255)");
+MODULE_PARM_DESC(ip_list_hash_size, "size of hash table used to look up IPs");
+MODULE_PARM_DESC(ip_list_perms, "permissions on /proc/net/ipt_recent/* files");
+
+
+struct recent_entry {
+ struct list_head list;
+ struct list_head lru_list;
+ u_int32_t addr;
+ u_int8_t ttl;
+ u_int8_t index;
+ u_int16_t nstamps;
+ unsigned long stamps[0];
};
-/* Structure of our linked list of tables of recent lists. */
-struct recent_ip_tables {
- char name[IPT_RECENT_NAME_LEN];
- int count;
- int time_pos;
- struct recent_ip_list *table;
- struct recent_ip_tables *next;
- spinlock_t list_lock;
- int *hash_table;
- struct time_info_list *time_info;
+struct recent_table {
+ struct list_head list;
+ char name[IPT_RECENT_NAME_LEN];
#ifdef CONFIG_PROC_FS
- struct proc_dir_entry *status_proc;
-#endif /* CONFIG_PROC_FS */
+ struct proc_dir_entry *proc;
+#endif
+ unsigned int refcnt;
+ unsigned int entries;
+ struct list_head lru_list;
+ struct list_head iphash[0];
};
-/* Our current list of addresses we have recently seen.
- * Only added to on a --set, and only updated on --set || --update
- */
-static struct recent_ip_tables *r_tables = NULL;
-
-/* We protect r_list with this spinlock so two processors are not modifying
- * the list at the same time.
- */
+static LIST_HEAD(tables);
static DEFINE_SPINLOCK(recent_lock);
#ifdef CONFIG_PROC_FS
-/* Our /proc/net/ipt_recent entry */
-static struct proc_dir_entry *proc_net_ipt_recent = NULL;
-#endif
-
-/* Function declaration for later. */
-static int
-match(const struct sk_buff *skb,
- const struct net_device *in,
- const struct net_device *out,
- const struct xt_match *match,
- const void *matchinfo,
- int offset,
- unsigned int protoff,
- int *hotdrop);
-
-/* Function to hash a given address into the hash table of table_size size */
-static int hash_func(unsigned int addr, int table_size)
-{
- int result = 0;
- unsigned int value = addr;
- do { result ^= value; } while((value >>= HASH_LOG));
-
-#ifdef DEBUG
- if(debug) printk(KERN_INFO RECENT_NAME ": %d = hash_func(%u,%d)\n",
- result & (table_size - 1),
- addr,
- table_size);
+static struct proc_dir_entry *proc_dir;
+static struct file_operations recent_fops;
#endif
- return(result & (table_size - 1));
-}
+static u_int32_t hash_rnd;
+static int hash_rnd_initted;
-#ifdef CONFIG_PROC_FS
-/* This is the function which produces the output for our /proc output
- * interface which lists each IP address, the last seen time and the
- * other recent times the address was seen.
- */
-
-static int ip_recent_get_info(char *buffer, char **start, off_t offset, int length, int *eof, void *data)
+static unsigned int recent_entry_hash(u_int32_t addr)
{
- int len = 0, count, last_len = 0, pkt_count;
- off_t pos = 0;
- off_t begin = 0;
- struct recent_ip_tables *curr_table;
-
- curr_table = (struct recent_ip_tables*) data;
-
- spin_lock_bh(&curr_table->list_lock);
- for(count = 0; count < ip_list_tot; count++) {
- if(!curr_table->table[count].addr) continue;
- last_len = len;
- len += sprintf(buffer+len,"src=%u.%u.%u.%u ",NIPQUAD(curr_table->table[count].addr));
- len += sprintf(buffer+len,"ttl: %u ",curr_table->table[count].ttl);
- len += sprintf(buffer+len,"last_seen: %lu ",curr_table->table[count].last_seen);
- len += sprintf(buffer+len,"oldest_pkt: %u ",curr_table->table[count].oldest_pkt);
- len += sprintf(buffer+len,"last_pkts: %lu",curr_table->table[count].last_pkts[0]);
- for(pkt_count = 1; pkt_count < ip_pkt_list_tot; pkt_count++) {
- if(!curr_table->table[count].last_pkts[pkt_count]) break;
- len += sprintf(buffer+len,", %lu",curr_table->table[count].last_pkts[pkt_count]);
- }
- len += sprintf(buffer+len,"\n");
- pos = begin + len;
- if(pos < offset) { len = 0; begin = pos; }
- if(pos > offset + length) { len = last_len; break; }
+ if (!hash_rnd_initted) {
+ get_random_bytes(&hash_rnd, 4);
+ hash_rnd_initted = 1;
}
-
- *start = buffer + (offset - begin);
- len -= (offset - begin);
- if(len > length) len = length;
-
- spin_unlock_bh(&curr_table->list_lock);
- return len;
+ return jhash_1word(addr, hash_rnd) & (ip_list_hash_size - 1);
}
-/* ip_recent_ctrl provides an interface for users to modify the table
- * directly. This allows adding entries, removing entries, and
- * flushing the entire table.
- * This is done by opening up the appropriate table for writing and
- * sending one of:
- * xx.xx.xx.xx -- Add entry to table with current time
- * +xx.xx.xx.xx -- Add entry to table with current time
- * -xx.xx.xx.xx -- Remove entry from table
- * clear -- Flush table, remove all entries
- */
-
-static int ip_recent_ctrl(struct file *file, const char __user *input, unsigned long size, void *data)
+static struct recent_entry *
+recent_entry_lookup(const struct recent_table *table, u_int32_t addr, u_int8_t ttl)
{
- static const u_int32_t max[4] = { 0xffffffff, 0xffffff, 0xffff, 0xff };
- u_int32_t val;
- int base, used = 0;
- char c, *cp;
- union iaddr {
- uint8_t bytes[4];
- uint32_t word;
- } res;
- uint8_t *pp = res.bytes;
- int digit;
-
- char buffer[20];
- int len, check_set = 0, count;
- u_int32_t addr = 0;
- struct sk_buff *skb;
- struct ipt_recent_info *info;
- struct recent_ip_tables *curr_table;
-
- curr_table = (struct recent_ip_tables*) data;
-
- if(size > 20) len = 20; else len = size;
-
- if(copy_from_user(buffer,input,len)) return -EFAULT;
-
- if(len < 20) buffer[len] = '\0';
-
-#ifdef DEBUG
- if(debug) printk(KERN_INFO RECENT_NAME ": ip_recent_ctrl len: %d, input: `%.20s'\n",len,buffer);
-#endif
+ struct recent_entry *e;
+ unsigned int h;
+
+ h = recent_entry_hash(addr);
+ list_for_each_entry(e, &table->iphash[h], list)
+ if (e->addr == addr && (ttl == e->ttl || !ttl || !e->ttl))
+ return e;
+ return NULL;
+}
- cp = buffer;
- while(isspace(*cp)) { cp++; used++; if(used >= len-5) return used; }
+static void recent_entry_remove(struct recent_table *t, struct recent_entry *e)
+{
+ list_del(&e->list);
+ list_del(&e->lru_list);
+ kfree(e);
+ t->entries--;
+}
- /* Check if we are asked to flush the entire table */
- if(!memcmp(cp,"clear",5)) {
- used += 5;
- spin_lock_bh(&curr_table->list_lock);
- curr_table->time_pos = 0;
- for(count = 0; count < ip_list_hash_size; count++) {
- curr_table->hash_table[count] = -1;
- }
- for(count = 0; count < ip_list_tot; count++) {
- curr_table->table[count].last_seen = 0;
- curr_table->table[count].addr = 0;
- curr_table->table[count].ttl = 0;
- memset(curr_table->table[count].last_pkts,0,ip_pkt_list_tot*sizeof(unsigned long));
- curr_table->table[count].oldest_pkt = 0;
- curr_table->table[count].time_pos = 0;
- curr_table->time_info[count].position = count;
- curr_table->time_info[count].time = 0;
- }
- spin_unlock_bh(&curr_table->list_lock);
- return used;
- }
+static struct recent_entry *
+recent_entry_init(struct recent_table *t, u_int32_t addr, u_int8_t ttl)
+{
+ struct recent_entry *e;
- check_set = IPT_RECENT_SET;
- switch(*cp) {
- case '+': check_set = IPT_RECENT_SET; cp++; used++; break;
- case '-': check_set = IPT_RECENT_REMOVE; cp++; used++; break;
- default: if(!isdigit(*cp)) return (used+1); break;
+ if (t->entries >= ip_list_tot) {
+ e = list_entry(t->lru_list.next, struct recent_entry, lru_list);
+ recent_entry_remove(t, e);
}
+ e = kmalloc(sizeof(*e) + sizeof(e->stamps[0]) * ip_pkt_list_tot,
+ GFP_ATOMIC);
+ if (e == NULL)
+ return NULL;
+ e->addr = addr;
+ e->ttl = ttl;
+ e->stamps[0] = jiffies;
+ e->nstamps = 1;
+ e->index = 1;
+ list_add_tail(&e->list, &t->iphash[recent_entry_hash(addr)]);
+ list_add_tail(&e->lru_list, &t->lru_list);
+ t->entries++;
+ return e;
+}
-#ifdef DEBUG
- if(debug) printk(KERN_INFO RECENT_NAME ": ip_recent_ctrl cp: `%c', check_set: %d\n",*cp,check_set);
-#endif
- /* Get addr (effectively inet_aton()) */
- /* Shamelessly stolen from libc, a function in the kernel for doing
- * this would, of course, be greatly preferred, but our options appear
- * to be rather limited, so we will just do it ourselves here.
- */
- res.word = 0;
-
- c = *cp;
- for(;;) {
- if(!isdigit(c)) return used;
- val = 0; base = 10; digit = 0;
- if(c == '0') {
- c = *++cp;
- if(c == 'x' || c == 'X') base = 16, c = *++cp;
- else { base = 8; digit = 1; }
- }
- for(;;) {
- if(isascii(c) && isdigit(c)) {
- if(base == 8 && (c == '8' || c == '0')) return used;
- val = (val * base) + (c - '0');
- c = *++cp;
- digit = 1;
- } else if(base == 16 && isascii(c) && isxdigit(c)) {
- val = (val << 4) | (c + 10 - (islower(c) ? 'a' : 'A'));
- c = *++cp;
- digit = 1;
- } else break;
- }
- if(c == '.') {
- if(pp > res.bytes + 2 || val > 0xff) return used;
- *pp++ = val;
- c = *++cp;
- } else break;
- }
- used = cp - buffer;
- if(c != '\0' && (!isascii(c) || !isspace(c))) return used;
- if(c == '\n') used++;
- if(!digit) return used;
+static void recent_entry_update(struct recent_table *t, struct recent_entry *e)
+{
+ e->stamps[e->index++] = jiffies;
+ if (e->index > e->nstamps)
+ e->nstamps = e->index;
+ e->index %= ip_pkt_list_tot;
+ list_move_tail(&e->lru_list, &t->lru_list);
+}
- if(val > max[pp - res.bytes]) return used;
- addr = res.word | htonl(val);
+static struct recent_table *recent_table_lookup(const char *name)
+{
+ struct recent_table *t;
- if(!addr && check_set == IPT_RECENT_SET) return used;
+ list_for_each_entry(t, &tables, list)
+ if (!strcmp(t->name, name))
+ return t;
+ return NULL;
+}
-#ifdef DEBUG
- if(debug) printk(KERN_INFO RECENT_NAME ": ip_recent_ctrl c: %c, addr: %u used: %d\n",c,addr,used);
-#endif
+static void recent_table_flush(struct recent_table *t)
+{
+ struct recent_entry *e, *next;
+ unsigned int i;
- /* Set up and just call match */
- info = kmalloc(sizeof(struct ipt_recent_info),GFP_KERNEL);
- if(!info) { return -ENOMEM; }
- info->seconds = 0;
- info->hit_count = 0;
- info->check_set = check_set;
- info->invert = 0;
- info->side = IPT_RECENT_SOURCE;
- strncpy(info->name,curr_table->name,IPT_RECENT_NAME_LEN);
- info->name[IPT_RECENT_NAME_LEN-1] = '\0';
-
- skb = kmalloc(sizeof(struct sk_buff),GFP_KERNEL);
- if (!skb) {
- used = -ENOMEM;
- goto out_free_info;
- }
- skb->nh.iph = kmalloc(sizeof(struct iphdr),GFP_KERNEL);
- if (!skb->nh.iph) {
- used = -ENOMEM;
- goto out_free_skb;
+ for (i = 0; i < ip_list_hash_size; i++) {
+ list_for_each_entry_safe(e, next, &t->iphash[i], list)
+ recent_entry_remove(t, e);
}
-
- skb->nh.iph->saddr = addr;
- skb->nh.iph->daddr = 0;
- /* Clear ttl since we have no way of knowing it */
- skb->nh.iph->ttl = 0;
- match(skb,NULL,NULL,NULL,info,0,0,NULL);
-
- kfree(skb->nh.iph);
-out_free_skb:
- kfree(skb);
-out_free_info:
- kfree(info);
-
-#ifdef DEBUG
- if(debug) printk(KERN_INFO RECENT_NAME ": Leaving ip_recent_ctrl addr: %u used: %d\n",addr,used);
-#endif
- return used;
}
-#endif /* CONFIG_PROC_FS */
-
-/* 'match' is our primary function, called by the kernel whenever a rule is
- * hit with our module as an option to it.
- * What this function does depends on what was specifically asked of it by
- * the user:
- * --set -- Add or update last seen time of the source address of the packet
- * -- matchinfo->check_set == IPT_RECENT_SET
- * --rcheck -- Just check if the source address is in the list
- * -- matchinfo->check_set == IPT_RECENT_CHECK
- * --update -- If the source address is in the list, update last_seen
- * -- matchinfo->check_set == IPT_RECENT_UPDATE
- * --remove -- If the source address is in the list, remove it
- * -- matchinfo->check_set == IPT_RECENT_REMOVE
- * --seconds -- Option to --rcheck/--update, only match if last_seen within seconds
- * -- matchinfo->seconds
- * --hitcount -- Option to --rcheck/--update, only match if seen hitcount times
- * -- matchinfo->hit_count
- * --seconds and --hitcount can be combined
- */
static int
-match(const struct sk_buff *skb,
- const struct net_device *in,
- const struct net_device *out,
- const struct xt_match *match,
- const void *matchinfo,
- int offset,
- unsigned int protoff,
- int *hotdrop)
+ipt_recent_match(const struct sk_buff *skb,
+ const struct net_device *in, const struct net_device *out,
+ const struct xt_match *match, const void *matchinfo,
+ int offset, unsigned int protoff, int *hotdrop)
{
- int pkt_count, hits_found, ans;
- unsigned long now;
const struct ipt_recent_info *info = matchinfo;
- u_int32_t addr = 0, time_temp;
- u_int8_t ttl = skb->nh.iph->ttl;
- int *hash_table;
- int orig_hash_result, hash_result, temp, location = 0, time_loc, end_collision_chain = -1;
- struct time_info_list *time_info;
- struct recent_ip_tables *curr_table;
- struct recent_ip_tables *last_table;
- struct recent_ip_list *r_list;
-
-#ifdef DEBUG
- if(debug) printk(KERN_INFO RECENT_NAME ": match() called\n");
-#endif
-
- /* Default is false ^ info->invert */
- ans = info->invert;
+ struct recent_table *t;
+ struct recent_entry *e;
+ u_int32_t addr;
+ u_int8_t ttl;
+ int ret = info->invert;
-#ifdef DEBUG
- if(debug) printk(KERN_INFO RECENT_NAME ": match(): name = '%s'\n",info->name);
-#endif
+ if (info->side == IPT_RECENT_DEST)
+ addr = skb->nh.iph->daddr;
+ else
+ addr = skb->nh.iph->saddr;
- /* if out != NULL then routing has been done and TTL changed.
- * We change it back here internally for match what came in before routing. */
- if(out) ttl++;
+ ttl = skb->nh.iph->ttl;
+ /* use TTL as seen before forwarding */
+ if (out && !skb->sk)
+ ttl++;
- /* Find the right table */
spin_lock_bh(&recent_lock);
- curr_table = r_tables;
- while( (last_table = curr_table) && strncmp(info->name,curr_table->name,IPT_RECENT_NAME_LEN) && (curr_table = curr_table->next) );
-
-#ifdef DEBUG
- if(debug) printk(KERN_INFO RECENT_NAME ": match(): table found('%s')\n",info->name);
-#endif
-
- spin_unlock_bh(&recent_lock);
-
- /* Table with this name not found, match impossible */
- if(!curr_table) { return ans; }
-
- /* Make sure no one is changing the list while we work with it */
- spin_lock_bh(&curr_table->list_lock);
-
- r_list = curr_table->table;
- if(info->side == IPT_RECENT_DEST) addr = skb->nh.iph->daddr; else addr = skb->nh.iph->saddr;
-
- if(!addr) {
-#ifdef DEBUG
- if(debug) printk(KERN_INFO RECENT_NAME ": match() address (%u) invalid, leaving.\n",addr);
-#endif
- spin_unlock_bh(&curr_table->list_lock);
- return ans;
+ t = recent_table_lookup(info->name);
+ e = recent_entry_lookup(t, addr,
+ info->check_set & IPT_RECENT_TTL ? ttl : 0);
+ if (e == NULL) {
+ if (!(info->check_set & IPT_RECENT_SET))
+ goto out;
+ e = recent_entry_init(t, addr, ttl);
+ if (e == NULL)
+ *hotdrop = 1;
+ ret ^= 1;
+ goto out;
}
-#ifdef DEBUG
- if(debug) printk(KERN_INFO RECENT_NAME ": match(): checking table, addr: %u, ttl: %u, orig_ttl: %u\n",addr,ttl,skb->nh.iph->ttl);
-#endif
-
- /* Get jiffies now in case they changed while we were waiting for a lock */
- now = jiffies;
- hash_table = curr_table->hash_table;
- time_info = curr_table->time_info;
-
- orig_hash_result = hash_result = hash_func(addr,ip_list_hash_size);
- /* Hash entry at this result used */
- /* Check for TTL match if requested. If TTL is zero then a match would never
- * happen, so match regardless of existing TTL in that case. Zero means the
- * entry was added via the /proc interface anyway, so we will just use the
- * first TTL we get for that IP address. */
- if(info->check_set & IPT_RECENT_TTL) {
- while(hash_table[hash_result] != -1 && !(r_list[hash_table[hash_result]].addr == addr &&
- (!r_list[hash_table[hash_result]].ttl || r_list[hash_table[hash_result]].ttl == ttl))) {
- /* Collision in hash table */
- hash_result = (hash_result + 1) % ip_list_hash_size;
- }
- } else {
- while(hash_table[hash_result] != -1 && r_list[hash_table[hash_result]].addr != addr) {
- /* Collision in hash table */
- hash_result = (hash_result + 1) % ip_list_hash_size;
- }
- }
-
- if(hash_table[hash_result] == -1 && !(info->check_set & IPT_RECENT_SET)) {
- /* IP not in list and not asked to SET */
- spin_unlock_bh(&curr_table->list_lock);
- return ans;
- }
-
- /* Check if we need to handle the collision, do not need to on REMOVE */
- if(orig_hash_result != hash_result && !(info->check_set & IPT_RECENT_REMOVE)) {
-#ifdef DEBUG
- if(debug) printk(KERN_INFO RECENT_NAME ": match(): Collision in hash table. (or: %d,hr: %d,oa: %u,ha: %u)\n",
- orig_hash_result,
- hash_result,
- r_list[hash_table[orig_hash_result]].addr,
- addr);
-#endif
-
- /* We had a collision.
- * orig_hash_result is where we started, hash_result is where we ended up.
- * So, swap them because we are likely to see the same guy again sooner */
-#ifdef DEBUG
- if(debug) {
- printk(KERN_INFO RECENT_NAME ": match(): Collision; hash_table[orig_hash_result] = %d\n",hash_table[orig_hash_result]);
- printk(KERN_INFO RECENT_NAME ": match(): Collision; r_list[hash_table[orig_hash_result]].hash_entry = %d\n",
- r_list[hash_table[orig_hash_result]].hash_entry);
- }
-#endif
-
- r_list[hash_table[orig_hash_result]].hash_entry = hash_result;
-
-
- temp = hash_table[orig_hash_result];
-#ifdef DEBUG
- if(debug) printk(KERN_INFO RECENT_NAME ": match(): Collision; hash_table[hash_result] = %d\n",hash_table[hash_result]);
-#endif
- hash_table[orig_hash_result] = hash_table[hash_result];
- hash_table[hash_result] = temp;
- temp = hash_result;
- hash_result = orig_hash_result;
- orig_hash_result = temp;
- time_info[r_list[hash_table[orig_hash_result]].time_pos].position = hash_table[orig_hash_result];
- if(hash_table[hash_result] != -1) {
- r_list[hash_table[hash_result]].hash_entry = hash_result;
- time_info[r_list[hash_table[hash_result]].time_pos].position = hash_table[hash_result];
- }
-
-#ifdef DEBUG
- if(debug) printk(KERN_INFO RECENT_NAME ": match(): Collision handled.\n");
-#endif
- }
-
- if(hash_table[hash_result] == -1) {
-#ifdef DEBUG
- if(debug) printk(KERN_INFO RECENT_NAME ": match(): New table entry. (hr: %d,ha: %u)\n",
- hash_result, addr);
-#endif
-
- /* New item found and IPT_RECENT_SET, so we need to add it */
- location = time_info[curr_table->time_pos].position;
- hash_table[r_list[location].hash_entry] = -1;
- hash_table[hash_result] = location;
- memset(r_list[location].last_pkts,0,ip_pkt_list_tot*sizeof(unsigned long));
- r_list[location].time_pos = curr_table->time_pos;
- r_list[location].addr = addr;
- r_list[location].ttl = ttl;
- r_list[location].last_seen = now;
- r_list[location].oldest_pkt = 1;
- r_list[location].last_pkts[0] = now;
- r_list[location].hash_entry = hash_result;
- time_info[curr_table->time_pos].time = r_list[location].last_seen;
- curr_table->time_pos = (curr_table->time_pos + 1) % ip_list_tot;
-
- ans = !info->invert;
- } else {
-#ifdef DEBUG
- if(debug) printk(KERN_INFO RECENT_NAME ": match(): Existing table entry. (hr: %d,ha: %u)\n",
- hash_result,
- addr);
-#endif
-
- /* Existing item found */
- location = hash_table[hash_result];
- /* We have a match on address, now to make sure it meets all requirements for a
- * full match. */
- if(info->check_set & IPT_RECENT_CHECK || info->check_set & IPT_RECENT_UPDATE) {
- if(!info->seconds && !info->hit_count) ans = !info->invert; else ans = info->invert;
- if(info->seconds && !info->hit_count) {
- if(time_before_eq(now,r_list[location].last_seen+info->seconds*HZ)) ans = !info->invert; else ans = info->invert;
- }
- if(info->seconds && info->hit_count) {
- for(pkt_count = 0, hits_found = 0; pkt_count < ip_pkt_list_tot; pkt_count++) {
- if(r_list[location].last_pkts[pkt_count] == 0) break;
- if(time_before_eq(now,r_list[location].last_pkts[pkt_count]+info->seconds*HZ)) hits_found++;
- }
- if(hits_found >= info->hit_count) ans = !info->invert; else ans = info->invert;
- }
- if(info->hit_count && !info->seconds) {
- for(pkt_count = 0, hits_found = 0; pkt_count < ip_pkt_list_tot; pkt_count++) {
- if(r_list[location].last_pkts[pkt_count] == 0) break;
- hits_found++;
- }
- if(hits_found >= info->hit_count) ans = !info->invert; else ans = info->invert;
- }
- }
-#ifdef DEBUG
- if(debug) {
- if(ans)
- printk(KERN_INFO RECENT_NAME ": match(): match addr: %u\n",addr);
- else
- printk(KERN_INFO RECENT_NAME ": match(): no match addr: %u\n",addr);
- }
-#endif
-
- /* If and only if we have been asked to SET, or to UPDATE (on match) do we add the
- * current timestamp to the last_seen. */
- if((info->check_set & IPT_RECENT_SET && (ans = !info->invert)) || (info->check_set & IPT_RECENT_UPDATE && ans)) {
-#ifdef DEBUG
- if(debug) printk(KERN_INFO RECENT_NAME ": match(): SET or UPDATE; updating time info.\n");
-#endif
- /* Have to update our time info */
- time_loc = r_list[location].time_pos;
- time_info[time_loc].time = now;
- time_info[time_loc].position = location;
- while((time_info[(time_loc+1) % ip_list_tot].time < time_info[time_loc].time) && ((time_loc+1) % ip_list_tot) != curr_table->time_pos) {
- time_temp = time_info[time_loc].time;
- time_info[time_loc].time = time_info[(time_loc+1)%ip_list_tot].time;
- time_info[(time_loc+1)%ip_list_tot].time = time_temp;
- time_temp = time_info[time_loc].position;
- time_info[time_loc].position = time_info[(time_loc+1)%ip_list_tot].position;
- time_info[(time_loc+1)%ip_list_tot].position = time_temp;
- r_list[time_info[time_loc].position].time_pos = time_loc;
- r_list[time_info[(time_loc+1)%ip_list_tot].position].time_pos = (time_loc+1)%ip_list_tot;
- time_loc = (time_loc+1) % ip_list_tot;
- }
- r_list[location].time_pos = time_loc;
- r_list[location].ttl = ttl;
- r_list[location].last_pkts[r_list[location].oldest_pkt] = now;
- r_list[location].oldest_pkt = ++r_list[location].oldest_pkt % ip_pkt_list_tot;
- r_list[location].last_seen = now;
- }
- /* If we have been asked to remove the entry from the list, just set it to 0 */
- if(info->check_set & IPT_RECENT_REMOVE) {
-#ifdef DEBUG
- if(debug) printk(KERN_INFO RECENT_NAME ": match(): REMOVE; clearing entry (or: %d, hr: %d).\n",orig_hash_result,hash_result);
-#endif
- /* Check if this is part of a collision chain */
- while(hash_table[(orig_hash_result+1) % ip_list_hash_size] != -1) {
- orig_hash_result++;
- if(hash_func(r_list[hash_table[orig_hash_result]].addr,ip_list_hash_size) == hash_result) {
- /* Found collision chain, how deep does this rabbit hole go? */
-#ifdef DEBUG
- if(debug) printk(KERN_INFO RECENT_NAME ": match(): REMOVE; found collision chain.\n");
-#endif
- end_collision_chain = orig_hash_result;
- }
- }
- if(end_collision_chain != -1) {
-#ifdef DEBUG
- if(debug) printk(KERN_INFO RECENT_NAME ": match(): REMOVE; part of collision chain, moving to end.\n");
-#endif
- /* Part of a collision chain, swap it with the end of the chain
- * before removing. */
- r_list[hash_table[end_collision_chain]].hash_entry = hash_result;
- temp = hash_table[end_collision_chain];
- hash_table[end_collision_chain] = hash_table[hash_result];
- hash_table[hash_result] = temp;
- time_info[r_list[hash_table[hash_result]].time_pos].position = hash_table[hash_result];
- hash_result = end_collision_chain;
- r_list[hash_table[hash_result]].hash_entry = hash_result;
- time_info[r_list[hash_table[hash_result]].time_pos].position = hash_table[hash_result];
- }
- location = hash_table[hash_result];
- hash_table[r_list[location].hash_entry] = -1;
- time_loc = r_list[location].time_pos;
- time_info[time_loc].time = 0;
- time_info[time_loc].position = location;
- while((time_info[(time_loc+1) % ip_list_tot].time < time_info[time_loc].time) && ((time_loc+1) % ip_list_tot) != curr_table->time_pos) {
- time_temp = time_info[time_loc].time;
- time_info[time_loc].time = time_info[(time_loc+1)%ip_list_tot].time;
- time_info[(time_loc+1)%ip_list_tot].time = time_temp;
- time_temp = time_info[time_loc].position;
- time_info[time_loc].position = time_info[(time_loc+1)%ip_list_tot].position;
- time_info[(time_loc+1)%ip_list_tot].position = time_temp;
- r_list[time_info[time_loc].position].time_pos = time_loc;
- r_list[time_info[(time_loc+1)%ip_list_tot].position].time_pos = (time_loc+1)%ip_list_tot;
- time_loc = (time_loc+1) % ip_list_tot;
+ if (info->check_set & IPT_RECENT_SET)
+ ret ^= 1;
+ else if (info->check_set & IPT_RECENT_REMOVE) {
+ recent_entry_remove(t, e);
+ ret ^= 1;
+ } else if (info->check_set & (IPT_RECENT_CHECK | IPT_RECENT_UPDATE)) {
+ unsigned long t = jiffies - info->seconds * HZ;
+ unsigned int i, hits = 0;
+
+ for (i = 0; i < e->nstamps; i++) {
+ if (info->seconds && time_after(t, e->stamps[i]))
+ continue;
+ if (++hits >= info->hit_count) {
+ ret ^= 1;
+ break;
}
- r_list[location].time_pos = time_loc;
- r_list[location].last_seen = 0;
- r_list[location].addr = 0;
- r_list[location].ttl = 0;
- memset(r_list[location].last_pkts,0,ip_pkt_list_tot*sizeof(unsigned long));
- r_list[location].oldest_pkt = 0;
- ans = !info->invert;
}
- spin_unlock_bh(&curr_table->list_lock);
- return ans;
}
- spin_unlock_bh(&curr_table->list_lock);
-#ifdef DEBUG
- if(debug) printk(KERN_INFO RECENT_NAME ": match() left.\n");
-#endif
- return ans;
+ if (info->check_set & IPT_RECENT_SET ||
+ (info->check_set & IPT_RECENT_UPDATE && ret)) {
+ recent_entry_update(t, e);
+ e->ttl = ttl;
+ }
+out:
+ spin_unlock_bh(&recent_lock);
+ return ret;
}
-/* This function is to verify that the rule given during the userspace iptables
- * command is correct.
- * If the command is valid then we check if the table name referred to by the
- * rule exists, if not it is created.
- */
static int
-checkentry(const char *tablename,
- const void *ip,
- const struct xt_match *match,
- void *matchinfo,
- unsigned int matchsize,
- unsigned int hook_mask)
+ipt_recent_checkentry(const char *tablename, const void *ip,
+ const struct xt_match *match, void *matchinfo,
+ unsigned int matchsize, unsigned int hook_mask)
{
- int flag = 0, c;
- unsigned long *hold;
const struct ipt_recent_info *info = matchinfo;
- struct recent_ip_tables *curr_table, *find_table, *last_table;
-
-#ifdef DEBUG
- if(debug) printk(KERN_INFO RECENT_NAME ": checkentry() entered.\n");
-#endif
-
- /* seconds and hit_count only valid for CHECK/UPDATE */
- if(info->check_set & IPT_RECENT_SET) { flag++; if(info->seconds || info->hit_count) return 0; }
- if(info->check_set & IPT_RECENT_REMOVE) { flag++; if(info->seconds || info->hit_count) return 0; }
- if(info->check_set & IPT_RECENT_CHECK) flag++;
- if(info->check_set & IPT_RECENT_UPDATE) flag++;
-
- /* One and only one of these should ever be set */
- if(flag != 1) return 0;
+ struct recent_table *t;
+ unsigned i;
+ int ret = 0;
- /* Name must be set to something */
- if(!info->name || !info->name[0]) return 0;
+ if (hweight8(info->check_set &
+ (IPT_RECENT_SET | IPT_RECENT_REMOVE |
+ IPT_RECENT_CHECK | IPT_RECENT_UPDATE)) != 1)
+ return 0;
+ if ((info->check_set & (IPT_RECENT_SET | IPT_RECENT_REMOVE)) &&
+ (info->seconds || info->hit_count))
+ return 0;
+ if (info->name[0] == '\0' ||
+ strnlen(info->name, IPT_RECENT_NAME_LEN) == IPT_RECENT_NAME_LEN)
+ return 0;
- /* Things look good, create a list for this if it does not exist */
- /* Lock the linked list while we play with it */
spin_lock_bh(&recent_lock);
-
- /* Look for an entry with this name already created */
- /* Finds the end of the list and the entry before the end if current name does not exist */
- find_table = r_tables;
- while( (last_table = find_table) && strncmp(info->name,find_table->name,IPT_RECENT_NAME_LEN) && (find_table = find_table->next) );
-
- /* If a table already exists just increment the count on that table and return */
- if(find_table) {
-#ifdef DEBUG
- if(debug) printk(KERN_INFO RECENT_NAME ": checkentry: table found (%s), incrementing count.\n",info->name);
-#endif
- find_table->count++;
- spin_unlock_bh(&recent_lock);
- return 1;
+ t = recent_table_lookup(info->name);
+ if (t != NULL) {
+ t->refcnt++;
+ ret = 1;
+ goto out;
}
- spin_unlock_bh(&recent_lock);
-
- /* Table with this name not found */
- /* Allocate memory for new linked list item */
-
-#ifdef DEBUG
- if(debug) {
- printk(KERN_INFO RECENT_NAME ": checkentry: no table found (%s)\n",info->name);
- printk(KERN_INFO RECENT_NAME ": checkentry: Allocationg %d for link-list entry.\n",sizeof(struct recent_ip_tables));
+ t = kzalloc(sizeof(*t) + sizeof(t->iphash[0]) * ip_list_hash_size,
+ GFP_ATOMIC);
+ if (t == NULL)
+ goto out;
+ strcpy(t->name, info->name);
+ INIT_LIST_HEAD(&t->lru_list);
+ for (i = 0; i < ip_list_hash_size; i++)
+ INIT_LIST_HEAD(&t->iphash[i]);
+#ifdef CONFIG_PROC_FS
+ t->proc = create_proc_entry(t->name, ip_list_perms, proc_dir);
+ if (t->proc == NULL) {
+ kfree(t);
+ goto out;
}
+ t->proc->proc_fops = &recent_fops;
+ t->proc->data = t;
#endif
+ list_add_tail(&t->list, &tables);
+ ret = 1;
+out:
+ spin_unlock_bh(&recent_lock);
+ return ret;
+}
- curr_table = vmalloc(sizeof(struct recent_ip_tables));
- if(curr_table == NULL) return 0;
-
- spin_lock_init(&curr_table->list_lock);
- curr_table->next = NULL;
- curr_table->count = 1;
- curr_table->time_pos = 0;
- strncpy(curr_table->name,info->name,IPT_RECENT_NAME_LEN);
- curr_table->name[IPT_RECENT_NAME_LEN-1] = '\0';
-
- /* Allocate memory for this table and the list of packets in each entry. */
-#ifdef DEBUG
- if(debug) printk(KERN_INFO RECENT_NAME ": checkentry: Allocating %d for table (%s).\n",
- sizeof(struct recent_ip_list)*ip_list_tot,
- info->name);
-#endif
-
- curr_table->table = vmalloc(sizeof(struct recent_ip_list)*ip_list_tot);
- if(curr_table->table == NULL) { vfree(curr_table); return 0; }
- memset(curr_table->table,0,sizeof(struct recent_ip_list)*ip_list_tot);
-#ifdef DEBUG
- if(debug) printk(KERN_INFO RECENT_NAME ": checkentry: Allocating %d for pkt_list.\n",
- sizeof(unsigned long)*ip_pkt_list_tot*ip_list_tot);
-#endif
-
- hold = vmalloc(sizeof(unsigned long)*ip_pkt_list_tot*ip_list_tot);
-#ifdef DEBUG
- if(debug) printk(KERN_INFO RECENT_NAME ": checkentry: After pkt_list allocation.\n");
-#endif
- if(hold == NULL) {
- printk(KERN_INFO RECENT_NAME ": checkentry: unable to allocate for pkt_list.\n");
- vfree(curr_table->table);
- vfree(curr_table);
- return 0;
- }
- for(c = 0; c < ip_list_tot; c++) {
- curr_table->table[c].last_pkts = hold + c*ip_pkt_list_tot;
- }
+static void
+ipt_recent_destroy(const struct xt_match *match, void *matchinfo,
+ unsigned int matchsize)
+{
+ const struct ipt_recent_info *info = matchinfo;
+ struct recent_table *t;
- /* Allocate memory for the hash table */
-#ifdef DEBUG
- if(debug) printk(KERN_INFO RECENT_NAME ": checkentry: Allocating %d for hash_table.\n",
- sizeof(int)*ip_list_hash_size);
+ spin_lock_bh(&recent_lock);
+ t = recent_table_lookup(info->name);
+ if (--t->refcnt == 0) {
+ list_del(&t->list);
+ recent_table_flush(t);
+#ifdef CONFIG_PROC_FS
+ remove_proc_entry(t->name, proc_dir);
#endif
-
- curr_table->hash_table = vmalloc(sizeof(int)*ip_list_hash_size);
- if(!curr_table->hash_table) {
- printk(KERN_INFO RECENT_NAME ": checkentry: unable to allocate for hash_table.\n");
- vfree(hold);
- vfree(curr_table->table);
- vfree(curr_table);
- return 0;
- }
-
- for(c = 0; c < ip_list_hash_size; c++) {
- curr_table->hash_table[c] = -1;
+ kfree(t);
}
+ spin_unlock_bh(&recent_lock);
+}
- /* Allocate memory for the time info */
-#ifdef DEBUG
- if(debug) printk(KERN_INFO RECENT_NAME ": checkentry: Allocating %d for time_info.\n",
- sizeof(struct time_info_list)*ip_list_tot);
-#endif
+#ifdef CONFIG_PROC_FS
+struct recent_iter_state {
+ struct recent_table *table;
+ unsigned int bucket;
+};
- curr_table->time_info = vmalloc(sizeof(struct time_info_list)*ip_list_tot);
- if(!curr_table->time_info) {
- printk(KERN_INFO RECENT_NAME ": checkentry: unable to allocate for time_info.\n");
- vfree(curr_table->hash_table);
- vfree(hold);
- vfree(curr_table->table);
- vfree(curr_table);
- return 0;
- }
- for(c = 0; c < ip_list_tot; c++) {
- curr_table->time_info[c].position = c;
- curr_table->time_info[c].time = 0;
- }
+static void *recent_seq_start(struct seq_file *seq, loff_t *pos)
+{
+ struct recent_iter_state *st = seq->private;
+ struct recent_table *t = st->table;
+ struct recent_entry *e;
+ loff_t p = *pos;
- /* Put the new table in place */
spin_lock_bh(&recent_lock);
- find_table = r_tables;
- while( (last_table = find_table) && strncmp(info->name,find_table->name,IPT_RECENT_NAME_LEN) && (find_table = find_table->next) );
-
- /* If a table already exists just increment the count on that table and return */
- if(find_table) {
- find_table->count++;
- spin_unlock_bh(&recent_lock);
-#ifdef DEBUG
- if(debug) printk(KERN_INFO RECENT_NAME ": checkentry: table found (%s), created by other process.\n",info->name);
-#endif
- vfree(curr_table->time_info);
- vfree(curr_table->hash_table);
- vfree(hold);
- vfree(curr_table->table);
- vfree(curr_table);
- return 1;
- }
- if(!last_table) r_tables = curr_table; else last_table->next = curr_table;
- spin_unlock_bh(&recent_lock);
-
-#ifdef CONFIG_PROC_FS
- /* Create our proc 'status' entry. */
- curr_table->status_proc = create_proc_entry(curr_table->name, ip_list_perms, proc_net_ipt_recent);
- if (!curr_table->status_proc) {
- vfree(hold);
- printk(KERN_INFO RECENT_NAME ": checkentry: unable to allocate for /proc entry.\n");
- /* Destroy the created table */
- spin_lock_bh(&recent_lock);
- last_table = NULL;
- curr_table = r_tables;
- if(!curr_table) {
-#ifdef DEBUG
- if(debug) printk(KERN_INFO RECENT_NAME ": checkentry() create_proc failed, no tables.\n");
-#endif
- spin_unlock_bh(&recent_lock);
- return 0;
- }
- while( strncmp(info->name,curr_table->name,IPT_RECENT_NAME_LEN) && (last_table = curr_table) && (curr_table = curr_table->next) );
- if(!curr_table) {
-#ifdef DEBUG
- if(debug) printk(KERN_INFO RECENT_NAME ": checkentry() create_proc failed, table already destroyed.\n");
-#endif
- spin_unlock_bh(&recent_lock);
- return 0;
+ for (st->bucket = 0; st->bucket < ip_list_hash_size; st->bucket++) {
+ list_for_each_entry(e, &t->iphash[st->bucket], list) {
+ if (p-- == 0)
+ return e;
}
- if(last_table) last_table->next = curr_table->next; else r_tables = curr_table->next;
- spin_unlock_bh(&recent_lock);
- vfree(curr_table->time_info);
- vfree(curr_table->hash_table);
- vfree(curr_table->table);
- vfree(curr_table);
- return 0;
}
-
- curr_table->status_proc->owner = THIS_MODULE;
- curr_table->status_proc->data = curr_table;
- wmb();
- curr_table->status_proc->read_proc = ip_recent_get_info;
- curr_table->status_proc->write_proc = ip_recent_ctrl;
-#endif /* CONFIG_PROC_FS */
-
-#ifdef DEBUG
- if(debug) printk(KERN_INFO RECENT_NAME ": checkentry() left.\n");
-#endif
+ return NULL;
+}
- return 1;
+static void *recent_seq_next(struct seq_file *seq, void *v, loff_t *pos)
+{
+ struct recent_iter_state *st = seq->private;
+ struct recent_table *t = st->table;
+ struct recent_entry *e = v;
+ struct list_head *head = e->list.next;
+
+ while (head == &t->iphash[st->bucket]) {
+ if (++st->bucket >= ip_list_hash_size)
+ return NULL;
+ head = t->iphash[st->bucket].next;
+ }
+ (*pos)++;
+ return list_entry(head, struct recent_entry, list);
}
-/* This function is called in the event that a rule matching this module is
- * removed.
- * When this happens we need to check if there are no other rules matching
- * the table given. If that is the case then we remove the table and clean
- * up its memory.
- */
-static void
-destroy(const struct xt_match *match, void *matchinfo, unsigned int matchsize)
+static void recent_seq_stop(struct seq_file *s, void *v)
{
- const struct ipt_recent_info *info = matchinfo;
- struct recent_ip_tables *curr_table, *last_table;
+ spin_unlock_bh(&recent_lock);
+}
-#ifdef DEBUG
- if(debug) printk(KERN_INFO RECENT_NAME ": destroy() entered.\n");
-#endif
+static int recent_seq_show(struct seq_file *seq, void *v)
+{
+ struct recent_entry *e = v;
+ unsigned int i;
+
+ i = (e->index - 1) % ip_pkt_list_tot;
+ seq_printf(seq, "src=%u.%u.%u.%u ttl: %u last_seen: %lu oldest_pkt: %u",
+ NIPQUAD(e->addr), e->ttl, e->stamps[i], e->index);
+ for (i = 0; i < e->nstamps; i++)
+ seq_printf(seq, "%s %lu", i ? "," : "", e->stamps[i]);
+ seq_printf(seq, "\n");
+ return 0;
+}
- if(matchsize != IPT_ALIGN(sizeof(struct ipt_recent_info))) return;
+static struct seq_operations recent_seq_ops = {
+ .start = recent_seq_start,
+ .next = recent_seq_next,
+ .stop = recent_seq_stop,
+ .show = recent_seq_show,
+};
- /* Lock the linked list while we play with it */
- spin_lock_bh(&recent_lock);
+static int recent_seq_open(struct inode *inode, struct file *file)
+{
+ struct proc_dir_entry *pde = PDE(inode);
+ struct seq_file *seq;
+ struct recent_iter_state *st;
+ int ret;
+
+ st = kzalloc(sizeof(*st), GFP_KERNEL);
+ if (st == NULL)
+ return -ENOMEM;
+ ret = seq_open(file, &recent_seq_ops);
+ if (ret)
+ kfree(st);
+ st->table = pde->data;
+ seq = file->private_data;
+ seq->private = st;
+ return ret;
+}
- /* Look for an entry with this name already created */
- /* Finds the end of the list and the entry before the end if current name does not exist */
- last_table = NULL;
- curr_table = r_tables;
- if(!curr_table) {
-#ifdef DEBUG
- if(debug) printk(KERN_INFO RECENT_NAME ": destroy() No tables found, leaving.\n");
-#endif
+static ssize_t recent_proc_write(struct file *file, const char __user *input,
+ size_t size, loff_t *loff)
+{
+ struct proc_dir_entry *pde = PDE(file->f_dentry->d_inode);
+ struct recent_table *t = pde->data;
+ struct recent_entry *e;
+ char buf[sizeof("+255.255.255.255")], *c = buf;
+ u_int32_t addr;
+ int add;
+
+ if (size > sizeof(buf))
+ size = sizeof(buf);
+ if (copy_from_user(buf, input, size))
+ return -EFAULT;
+ while (isspace(*c))
+ c++;
+
+ if (size - (c - buf) < 5)
+ return c - buf;
+ if (!strncmp(c, "clear", 5)) {
+ c += 5;
+ spin_lock_bh(&recent_lock);
+ recent_table_flush(t);
spin_unlock_bh(&recent_lock);
- return;
+ return c - buf;
}
- while( strncmp(info->name,curr_table->name,IPT_RECENT_NAME_LEN) && (last_table = curr_table) && (curr_table = curr_table->next) );
- /* If a table does not exist then do nothing and return */
- if(!curr_table) {
-#ifdef DEBUG
- if(debug) printk(KERN_INFO RECENT_NAME ": destroy() table not found, leaving.\n");
-#endif
- spin_unlock_bh(&recent_lock);
- return;
+ switch (*c) {
+ case '-':
+ add = 0;
+ c++;
+ break;
+ case '+':
+ c++;
+ default:
+ add = 1;
+ break;
}
+ addr = in_aton(c);
- curr_table->count--;
-
- /* If count is still non-zero then there are still rules referenceing it so we do nothing */
- if(curr_table->count) {
-#ifdef DEBUG
- if(debug) printk(KERN_INFO RECENT_NAME ": destroy() table found, non-zero count, leaving.\n");
-#endif
- spin_unlock_bh(&recent_lock);
- return;
+ spin_lock_bh(&recent_lock);
+ e = recent_entry_lookup(t, addr, 0);
+ if (e == NULL) {
+ if (add)
+ recent_entry_init(t, addr, 0);
+ } else {
+ if (add)
+ recent_entry_update(t, e);
+ else
+ recent_entry_remove(t, e);
}
-
-#ifdef DEBUG
- if(debug) printk(KERN_INFO RECENT_NAME ": destroy() table found, zero count, removing.\n");
-#endif
-
- /* Count must be zero so we remove this table from the list */
- if(last_table) last_table->next = curr_table->next; else r_tables = curr_table->next;
-
spin_unlock_bh(&recent_lock);
+ return size;
+}
- /* lock to make sure any late-runners still using this after we removed it from
- * the list finish up then remove everything */
- spin_lock_bh(&curr_table->list_lock);
- spin_unlock_bh(&curr_table->list_lock);
-
-#ifdef CONFIG_PROC_FS
- if(curr_table->status_proc) remove_proc_entry(curr_table->name,proc_net_ipt_recent);
+static struct file_operations recent_fops = {
+ .open = recent_seq_open,
+ .read = seq_read,
+ .write = recent_proc_write,
+ .release = seq_release_private,
+ .owner = THIS_MODULE,
+};
#endif /* CONFIG_PROC_FS */
- vfree(curr_table->table[0].last_pkts);
- vfree(curr_table->table);
- vfree(curr_table->hash_table);
- vfree(curr_table->time_info);
- vfree(curr_table);
-
-#ifdef DEBUG
- if(debug) printk(KERN_INFO RECENT_NAME ": destroy() left.\n");
-#endif
- return;
-}
-
-/* This is the structure we pass to ipt_register to register our
- * module with iptables.
- */
static struct ipt_match recent_match = {
.name = "recent",
- .match = match,
+ .match = ipt_recent_match,
.matchsize = sizeof(struct ipt_recent_info),
- .checkentry = checkentry,
- .destroy = destroy,
- .me = THIS_MODULE
+ .checkentry = ipt_recent_checkentry,
+ .destroy = ipt_recent_destroy,
+ .me = THIS_MODULE,
};
-/* Kernel module initialization. */
static int __init ipt_recent_init(void)
{
- int err, count;
+ int err;
- printk(version);
-#ifdef CONFIG_PROC_FS
- proc_net_ipt_recent = proc_mkdir("ipt_recent",proc_net);
- if(!proc_net_ipt_recent) return -ENOMEM;
-#endif
-
- if(ip_list_hash_size && ip_list_hash_size <= ip_list_tot) {
- printk(KERN_WARNING RECENT_NAME ": ip_list_hash_size too small, resetting to default.\n");
- ip_list_hash_size = 0;
- }
-
- if(!ip_list_hash_size) {
- ip_list_hash_size = ip_list_tot*3;
- count = 2*2;
- while(ip_list_hash_size > count) count = count*2;
- ip_list_hash_size = count;
- }
-
-#ifdef DEBUG
- if(debug) printk(KERN_INFO RECENT_NAME ": ip_list_hash_size: %d\n",ip_list_hash_size);
-#endif
+ if (!ip_list_tot || !ip_pkt_list_tot || ip_pkt_list_tot > 255)
+ return -EINVAL;
+ ip_list_hash_size = 1 << fls(ip_list_tot);
err = ipt_register_match(&recent_match);
+#ifdef CONFIG_PROC_FS
if (err)
- remove_proc_entry("ipt_recent", proc_net);
+ return err;
+ proc_dir = proc_mkdir("ipt_recent", proc_net);
+ if (proc_dir == NULL) {
+ ipt_unregister_match(&recent_match);
+ err = -ENOMEM;
+ }
+#endif
return err;
}
-/* Kernel module destruction. */
-static void __exit ipt_recent_fini(void)
+static void __exit ipt_recent_exit(void)
{
+ BUG_ON(!list_empty(&tables));
ipt_unregister_match(&recent_match);
-
- remove_proc_entry("ipt_recent",proc_net);
+#ifdef CONFIG_PROC_FS
+ remove_proc_entry("ipt_recent", proc_net);
+#endif
}
-/* Register our module with the kernel. */
module_init(ipt_recent_init);
-module_exit(ipt_recent_fini);
+module_exit(ipt_recent_exit);
^ permalink raw reply related [flat|nested] 23+ messages in thread* Re: [NETFILTER 05/17]: recent match: replace by rewritten version
2006-05-29 22:34 ` [NETFILTER 05/17]: recent match: replace by rewritten version Patrick McHardy
@ 2006-05-30 13:11 ` Stephen Frost
2006-05-30 13:16 ` Patrick McHardy
0 siblings, 1 reply; 23+ messages in thread
From: Stephen Frost @ 2006-05-30 13:11 UTC (permalink / raw)
To: Patrick McHardy; +Cc: netfilter-devel, davem
[-- Attachment #1: Type: text/plain, Size: 555 bytes --]
* Patrick McHardy (kaber@trash.net) wrote:
> [NETFILTER]: recent match: replace by rewritten version
I havn't had a chance to check yet, but was something done about the
last round of issues I pointed out? Specifically, concerns that entries
in the table which are never updated will not end up in the list to be
candidates for deletion due to the eviction policy? I don't think it'd
be a good plan to move to this till that's fixed (it's not hard to fix,
either).
I'll try and get a chance to re-review it, again, later today...
Thanks,
Stephen
[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 189 bytes --]
^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [NETFILTER 05/17]: recent match: replace by rewritten version
2006-05-30 13:11 ` Stephen Frost
@ 2006-05-30 13:16 ` Patrick McHardy
2006-05-30 18:10 ` Stephen Frost
0 siblings, 1 reply; 23+ messages in thread
From: Patrick McHardy @ 2006-05-30 13:16 UTC (permalink / raw)
To: Stephen Frost; +Cc: netfilter-devel, davem
Stephen Frost wrote:
> * Patrick McHardy (kaber@trash.net) wrote:
>
>>[NETFILTER]: recent match: replace by rewritten version
>
>
> I havn't had a chance to check yet, but was something done about the
> last round of issues I pointed out? Specifically, concerns that entries
> in the table which are never updated will not end up in the list to be
> candidates for deletion due to the eviction policy? I don't think it'd
> be a good plan to move to this till that's fixed (it's not hard to fix,
> either).
Already fixed.
^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [NETFILTER 05/17]: recent match: replace by rewritten version
2006-05-30 13:16 ` Patrick McHardy
@ 2006-05-30 18:10 ` Stephen Frost
2006-05-31 0:48 ` Patrick McHardy
0 siblings, 1 reply; 23+ messages in thread
From: Stephen Frost @ 2006-05-30 18:10 UTC (permalink / raw)
To: Patrick McHardy; +Cc: netfilter-devel, davem
[-- Attachment #1: Type: text/plain, Size: 779 bytes --]
* Patrick McHardy (kaber@trash.net) wrote:
> Stephen Frost wrote:
> > I havn't had a chance to check yet, but was something done about the
> > last round of issues I pointed out? Specifically, concerns that entries
> > in the table which are never updated will not end up in the list to be
> > candidates for deletion due to the eviction policy? I don't think it'd
> > be a good plan to move to this till that's fixed (it's not hard to fix,
> > either).
>
> Already fixed.
Great, thanks. I've now reviewed the version in DaveM's net-2.6.18 git
tree and it looks good to me. I'll try and do some real-world testing
on it this weekend. I'm very curious if these changes will allow for
larger lists than was previously possible.
Thanks again,
Stephen
[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 189 bytes --]
^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [NETFILTER 05/17]: recent match: replace by rewritten version
2006-05-30 18:10 ` Stephen Frost
@ 2006-05-31 0:48 ` Patrick McHardy
0 siblings, 0 replies; 23+ messages in thread
From: Patrick McHardy @ 2006-05-31 0:48 UTC (permalink / raw)
To: Stephen Frost; +Cc: netfilter-devel, davem
Stephen Frost wrote:
> Great, thanks. I've now reviewed the version in DaveM's net-2.6.18 git
> tree and it looks good to me. I'll try and do some real-world testing
> on it this weekend. I'm very curious if these changes will allow for
> larger lists than was previously possible.
Thanks Stephen, I appreciate your help getting rid of the problem.
It should perform a lot better with large lists, the closed hash
with linear probing looked horribly inefficient.
^ permalink raw reply [flat|nested] 23+ messages in thread
* [NETFILTER 06/17]: conntrack: don't call helpers for related ICMP messages
2006-05-29 22:34 [NETFILTER 00/17]: Netfilter update for 2.6.18 Patrick McHardy
` (4 preceding siblings ...)
2006-05-29 22:34 ` [NETFILTER 05/17]: recent match: replace by rewritten version Patrick McHardy
@ 2006-05-29 22:34 ` Patrick McHardy
2006-05-29 22:34 ` [NETFILTER 07/17]: conntrack: add sysctl to disable checksumming Patrick McHardy
` (11 subsequent siblings)
17 siblings, 0 replies; 23+ messages in thread
From: Patrick McHardy @ 2006-05-29 22:34 UTC (permalink / raw)
To: davem; +Cc: netfilter-devel, Patrick McHardy
[NETFILTER]: conntrack: don't call helpers for related ICMP messages
None of the existing helpers expects to get called for related ICMP
packets and some even drop them if they can't parse them.
Signed-off-by: Patrick McHardy <kaber@trash.net>
---
commit ee0877ce5fb4e72afee68e2c393d86ac64e69afe
tree 56960aeb26e21354aa619d687172541162adcea7
parent ac0eb5fe3ab7b4637f208b8dc79a5446e4d59dea
author Patrick McHardy <kaber@trash.net> Tue, 30 May 2006 00:02:42 +0200
committer Patrick McHardy <kaber@trash.net> Tue, 30 May 2006 00:02:42 +0200
net/ipv4/netfilter/ip_conntrack_standalone.c | 2 +-
net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c | 2 +-
net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c | 2 +-
3 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/net/ipv4/netfilter/ip_conntrack_standalone.c b/net/ipv4/netfilter/ip_conntrack_standalone.c
index 929d61f..f0cc7fe 100644
--- a/net/ipv4/netfilter/ip_conntrack_standalone.c
+++ b/net/ipv4/netfilter/ip_conntrack_standalone.c
@@ -417,7 +417,7 @@ static unsigned int ip_conntrack_help(un
/* This is where we call the helper: as the packet goes out. */
ct = ip_conntrack_get(*pskb, &ctinfo);
- if (ct && ct->helper) {
+ if (ct && ct->helper && ctinfo != IP_CT_RELATED + IP_CT_IS_REPLY) {
unsigned int ret;
ret = ct->helper->help(pskb, ct, ctinfo);
if (ret != NF_ACCEPT)
diff --git a/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c
index 5bc9f64..5b43945 100644
--- a/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c
+++ b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c
@@ -145,7 +145,7 @@ static unsigned int ipv4_conntrack_help(
/* This is where we call the helper: as the packet goes out. */
ct = nf_ct_get(*pskb, &ctinfo);
- if (!ct)
+ if (!ct || ctinfo == IP_CT_RELATED + IP_CT_IS_REPLY)
return NF_ACCEPT;
help = nfct_help(ct);
diff --git a/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c b/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c
index 93bae36..2a71c3b 100644
--- a/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c
+++ b/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c
@@ -189,7 +189,7 @@ static unsigned int ipv6_confirm(unsigne
/* This is where we call the helper: as the packet goes out. */
ct = nf_ct_get(*pskb, &ctinfo);
- if (!ct)
+ if (!ct || ctinfo == IP_CT_RELATED + IP_CT_IS_REPLY)
goto out;
help = nfct_help(ct);
^ permalink raw reply related [flat|nested] 23+ messages in thread* [NETFILTER 07/17]: conntrack: add sysctl to disable checksumming
2006-05-29 22:34 [NETFILTER 00/17]: Netfilter update for 2.6.18 Patrick McHardy
` (5 preceding siblings ...)
2006-05-29 22:34 ` [NETFILTER 06/17]: conntrack: don't call helpers for related ICMP messages Patrick McHardy
@ 2006-05-29 22:34 ` Patrick McHardy
2006-05-29 22:34 ` [NETFILTER 08/17]: conntrack: add fixed timeout flag in connection tracking Patrick McHardy
` (10 subsequent siblings)
17 siblings, 0 replies; 23+ messages in thread
From: Patrick McHardy @ 2006-05-29 22:34 UTC (permalink / raw)
To: davem; +Cc: netfilter-devel, Patrick McHardy
[NETFILTER]: conntrack: add sysctl to disable checksumming
Signed-off-by: Patrick McHardy <kaber@trash.net>
---
commit 951256425de86a32569c787ff827554314026824
tree 604ff1fd7cdfe02990d34d78a8da24e38bbe05ab
parent ee0877ce5fb4e72afee68e2c393d86ac64e69afe
author Patrick McHardy <kaber@trash.net> Tue, 30 May 2006 00:02:44 +0200
committer Patrick McHardy <kaber@trash.net> Tue, 30 May 2006 00:02:44 +0200
include/linux/netfilter_ipv4/ip_conntrack.h | 1 +
include/linux/sysctl.h | 2 ++
include/net/netfilter/nf_conntrack.h | 1 +
net/ipv4/netfilter/ip_conntrack_proto_icmp.c | 2 +-
net/ipv4/netfilter/ip_conntrack_proto_tcp.c | 2 +-
net/ipv4/netfilter/ip_conntrack_proto_udp.c | 2 +-
net/ipv4/netfilter/ip_conntrack_standalone.c | 11 +++++++++++
net/ipv4/netfilter/nf_conntrack_proto_icmp.c | 2 +-
net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c | 2 +-
net/netfilter/nf_conntrack_proto_tcp.c | 5 +++--
net/netfilter/nf_conntrack_proto_udp.c | 3 ++-
net/netfilter/nf_conntrack_standalone.c | 11 +++++++++++
12 files changed, 36 insertions(+), 8 deletions(-)
diff --git a/include/linux/netfilter_ipv4/ip_conntrack.h b/include/linux/netfilter_ipv4/ip_conntrack.h
index d54d7b2..5473c01 100644
--- a/include/linux/netfilter_ipv4/ip_conntrack.h
+++ b/include/linux/netfilter_ipv4/ip_conntrack.h
@@ -293,6 +293,7 @@ static inline int is_dying(struct ip_con
}
extern unsigned int ip_conntrack_htable_size;
+extern int ip_conntrack_checksum;
#define CONNTRACK_STAT_INC(count) (__get_cpu_var(ip_conntrack_stat).count++)
diff --git a/include/linux/sysctl.h b/include/linux/sysctl.h
index cd9e7c0..98338ed 100644
--- a/include/linux/sysctl.h
+++ b/include/linux/sysctl.h
@@ -313,6 +313,7 @@ enum
NET_NF_CONNTRACK_FRAG6_TIMEOUT=29,
NET_NF_CONNTRACK_FRAG6_LOW_THRESH=30,
NET_NF_CONNTRACK_FRAG6_HIGH_THRESH=31,
+ NET_NF_CONNTRACK_CHECKSUM=32,
};
/* /proc/sys/net/ipv4 */
@@ -492,6 +493,7 @@ enum
NET_IPV4_NF_CONNTRACK_SCTP_TIMEOUT_SHUTDOWN_RECD=25,
NET_IPV4_NF_CONNTRACK_SCTP_TIMEOUT_SHUTDOWN_ACK_SENT=26,
NET_IPV4_NF_CONNTRACK_COUNT=27,
+ NET_IPV4_NF_CONNTRACK_CHECKSUM=28,
};
/* /proc/sys/net/ipv6 */
diff --git a/include/net/netfilter/nf_conntrack.h b/include/net/netfilter/nf_conntrack.h
index 916013c..dbe7a11 100644
--- a/include/net/netfilter/nf_conntrack.h
+++ b/include/net/netfilter/nf_conntrack.h
@@ -285,6 +285,7 @@ static inline int nf_ct_is_dying(struct
}
extern unsigned int nf_conntrack_htable_size;
+extern int nf_conntrack_checksum;
#define NF_CT_STAT_INC(count) (__get_cpu_var(nf_conntrack_stat).count++)
diff --git a/net/ipv4/netfilter/ip_conntrack_proto_icmp.c b/net/ipv4/netfilter/ip_conntrack_proto_icmp.c
index d8b14a9..23f1c50 100644
--- a/net/ipv4/netfilter/ip_conntrack_proto_icmp.c
+++ b/net/ipv4/netfilter/ip_conntrack_proto_icmp.c
@@ -224,7 +224,7 @@ icmp_error(struct sk_buff *skb, enum ip_
}
/* See ip_conntrack_proto_tcp.c */
- if (hooknum == NF_IP_PRE_ROUTING &&
+ if (ip_conntrack_checksum && hooknum == NF_IP_PRE_ROUTING &&
nf_ip_checksum(skb, hooknum, skb->nh.iph->ihl * 4, 0)) {
if (LOG_INVALID(IPPROTO_ICMP))
nf_log_packet(PF_INET, 0, skb, NULL, NULL, NULL,
diff --git a/net/ipv4/netfilter/ip_conntrack_proto_tcp.c b/net/ipv4/netfilter/ip_conntrack_proto_tcp.c
index 062b252..c5c2ce5 100644
--- a/net/ipv4/netfilter/ip_conntrack_proto_tcp.c
+++ b/net/ipv4/netfilter/ip_conntrack_proto_tcp.c
@@ -870,7 +870,7 @@ static int tcp_error(struct sk_buff *skb
* and moreover root might send raw packets.
*/
/* FIXME: Source route IP option packets --RR */
- if (hooknum == NF_IP_PRE_ROUTING &&
+ if (ip_conntrack_checksum && hooknum == NF_IP_PRE_ROUTING &&
nf_ip_checksum(skb, hooknum, iph->ihl * 4, IPPROTO_TCP)) {
if (LOG_INVALID(IPPROTO_TCP))
nf_log_packet(PF_INET, 0, skb, NULL, NULL, NULL,
diff --git a/net/ipv4/netfilter/ip_conntrack_proto_udp.c b/net/ipv4/netfilter/ip_conntrack_proto_udp.c
index 7089986..9b2c16b 100644
--- a/net/ipv4/netfilter/ip_conntrack_proto_udp.c
+++ b/net/ipv4/netfilter/ip_conntrack_proto_udp.c
@@ -120,7 +120,7 @@ static int udp_error(struct sk_buff *skb
* because the semantic of CHECKSUM_HW is different there
* and moreover root might send raw packets.
* FIXME: Source route IP option packets --RR */
- if (hooknum == NF_IP_PRE_ROUTING &&
+ if (ip_conntrack_checksum && hooknum == NF_IP_PRE_ROUTING &&
nf_ip_checksum(skb, hooknum, iph->ihl * 4, IPPROTO_UDP)) {
if (LOG_INVALID(IPPROTO_UDP))
nf_log_packet(PF_INET, 0, skb, NULL, NULL, NULL,
diff --git a/net/ipv4/netfilter/ip_conntrack_standalone.c b/net/ipv4/netfilter/ip_conntrack_standalone.c
index f0cc7fe..6cb9b98 100644
--- a/net/ipv4/netfilter/ip_conntrack_standalone.c
+++ b/net/ipv4/netfilter/ip_conntrack_standalone.c
@@ -564,6 +564,8 @@ extern unsigned int ip_ct_generic_timeou
static int log_invalid_proto_min = 0;
static int log_invalid_proto_max = 255;
+int ip_conntrack_checksum = 1;
+
static struct ctl_table_header *ip_ct_sysctl_header;
static ctl_table ip_ct_sysctl_table[] = {
@@ -592,6 +594,14 @@ static ctl_table ip_ct_sysctl_table[] =
.proc_handler = &proc_dointvec,
},
{
+ .ctl_name = NET_IPV4_NF_CONNTRACK_CHECKSUM,
+ .procname = "ip_conntrack_checksum",
+ .data = &ip_conntrack_checksum,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = &proc_dointvec,
+ },
+ {
.ctl_name = NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_SYN_SENT,
.procname = "ip_conntrack_tcp_timeout_syn_sent",
.data = &ip_ct_tcp_timeout_syn_sent,
@@ -946,6 +956,7 @@ EXPORT_SYMBOL_GPL(__ip_conntrack_helper_
EXPORT_SYMBOL_GPL(ip_conntrack_proto_find_get);
EXPORT_SYMBOL_GPL(ip_conntrack_proto_put);
EXPORT_SYMBOL_GPL(__ip_conntrack_proto_find);
+EXPORT_SYMBOL_GPL(ip_conntrack_checksum);
#if defined(CONFIG_IP_NF_CONNTRACK_NETLINK) || \
defined(CONFIG_IP_NF_CONNTRACK_NETLINK_MODULE)
EXPORT_SYMBOL_GPL(ip_ct_port_tuple_to_nfattr);
diff --git a/net/ipv4/netfilter/nf_conntrack_proto_icmp.c b/net/ipv4/netfilter/nf_conntrack_proto_icmp.c
index 4b0d361..663a73e 100644
--- a/net/ipv4/netfilter/nf_conntrack_proto_icmp.c
+++ b/net/ipv4/netfilter/nf_conntrack_proto_icmp.c
@@ -235,7 +235,7 @@ icmp_error(struct sk_buff *skb, unsigned
}
/* See ip_conntrack_proto_tcp.c */
- if (hooknum == NF_IP_PRE_ROUTING &&
+ if (nf_conntrack_checksum && hooknum == NF_IP_PRE_ROUTING &&
nf_ip_checksum(skb, hooknum, dataoff, 0)) {
if (LOG_INVALID(IPPROTO_ICMP))
nf_log_packet(PF_INET, 0, skb, NULL, NULL, NULL,
diff --git a/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c b/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c
index 86c6703..ef18a7b 100644
--- a/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c
+++ b/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c
@@ -233,7 +233,7 @@ icmpv6_error(struct sk_buff *skb, unsign
return -NF_ACCEPT;
}
- if (hooknum == NF_IP6_PRE_ROUTING &&
+ if (nf_conntrack_checksum && hooknum == NF_IP6_PRE_ROUTING &&
nf_ip6_checksum(skb, hooknum, dataoff, IPPROTO_ICMPV6)) {
nf_log_packet(PF_INET6, 0, skb, NULL, NULL, NULL,
"nf_ct_icmpv6: ICMPv6 checksum failed\n");
diff --git a/net/netfilter/nf_conntrack_proto_tcp.c b/net/netfilter/nf_conntrack_proto_tcp.c
index 69899f2..12fb7c0 100644
--- a/net/netfilter/nf_conntrack_proto_tcp.c
+++ b/net/netfilter/nf_conntrack_proto_tcp.c
@@ -828,8 +828,9 @@ static int tcp_error(struct sk_buff *skb
* and moreover root might send raw packets.
*/
/* FIXME: Source route IP option packets --RR */
- if (((pf == PF_INET && hooknum == NF_IP_PRE_ROUTING) ||
- (pf == PF_INET6 && hooknum == NF_IP6_PRE_ROUTING)) &&
+ if (nf_conntrack_checksum &&
+ ((pf == PF_INET && hooknum == NF_IP_PRE_ROUTING) ||
+ (pf == PF_INET6 && hooknum == NF_IP6_PRE_ROUTING)) &&
nf_checksum(skb, hooknum, dataoff, IPPROTO_TCP, pf)) {
if (LOG_INVALID(IPPROTO_TCP))
nf_log_packet(pf, 0, skb, NULL, NULL, NULL,
diff --git a/net/netfilter/nf_conntrack_proto_udp.c b/net/netfilter/nf_conntrack_proto_udp.c
index d93edbf..ae07ebe 100644
--- a/net/netfilter/nf_conntrack_proto_udp.c
+++ b/net/netfilter/nf_conntrack_proto_udp.c
@@ -134,7 +134,8 @@ static int udp_error(struct sk_buff *skb
* because the semantic of CHECKSUM_HW is different there
* and moreover root might send raw packets.
* FIXME: Source route IP option packets --RR */
- if (((pf == PF_INET && hooknum == NF_IP_PRE_ROUTING) ||
+ if (nf_conntrack_checksum &&
+ ((pf == PF_INET && hooknum == NF_IP_PRE_ROUTING) ||
(pf == PF_INET6 && hooknum == NF_IP6_PRE_ROUTING)) &&
nf_checksum(skb, hooknum, dataoff, IPPROTO_UDP, pf)) {
if (LOG_INVALID(IPPROTO_UDP))
diff --git a/net/netfilter/nf_conntrack_standalone.c b/net/netfilter/nf_conntrack_standalone.c
index 408960c..e01d20d 100644
--- a/net/netfilter/nf_conntrack_standalone.c
+++ b/net/netfilter/nf_conntrack_standalone.c
@@ -455,6 +455,8 @@ extern unsigned int nf_ct_generic_timeou
static int log_invalid_proto_min = 0;
static int log_invalid_proto_max = 255;
+int nf_conntrack_checksum = 1;
+
static struct ctl_table_header *nf_ct_sysctl_header;
static ctl_table nf_ct_sysctl_table[] = {
@@ -483,6 +485,14 @@ static ctl_table nf_ct_sysctl_table[] =
.proc_handler = &proc_dointvec,
},
{
+ .ctl_name = NET_NF_CONNTRACK_CHECKSUM,
+ .procname = "nf_conntrack_checksum",
+ .data = &nf_conntrack_checksum,
+ .maxlen = sizeof(unsigned int),
+ .mode = 0644,
+ .proc_handler = &proc_dointvec,
+ },
+ {
.ctl_name = NET_NF_CONNTRACK_TCP_TIMEOUT_SYN_SENT,
.procname = "nf_conntrack_tcp_timeout_syn_sent",
.data = &nf_ct_tcp_timeout_syn_sent,
@@ -851,6 +861,7 @@ EXPORT_SYMBOL(nf_ct_proto_put);
EXPORT_SYMBOL(nf_ct_l3proto_find_get);
EXPORT_SYMBOL(nf_ct_l3proto_put);
EXPORT_SYMBOL(nf_ct_l3protos);
+EXPORT_SYMBOL_GPL(nf_conntrack_checksum);
EXPORT_SYMBOL(nf_conntrack_expect_alloc);
EXPORT_SYMBOL(nf_conntrack_expect_put);
EXPORT_SYMBOL(nf_conntrack_expect_related);
^ permalink raw reply related [flat|nested] 23+ messages in thread* [NETFILTER 08/17]: conntrack: add fixed timeout flag in connection tracking
2006-05-29 22:34 [NETFILTER 00/17]: Netfilter update for 2.6.18 Patrick McHardy
` (6 preceding siblings ...)
2006-05-29 22:34 ` [NETFILTER 07/17]: conntrack: add sysctl to disable checksumming Patrick McHardy
@ 2006-05-29 22:34 ` Patrick McHardy
2006-05-29 22:34 ` [NETFILTER 09/17]: ctnetlink: fix NAT configuration Patrick McHardy
` (9 subsequent siblings)
17 siblings, 0 replies; 23+ messages in thread
From: Patrick McHardy @ 2006-05-29 22:34 UTC (permalink / raw)
To: davem; +Cc: netfilter-devel, Patrick McHardy
[NETFILTER]: conntrack: add fixed timeout flag in connection tracking
Add a flag in a connection status to have a non updated timeout.
This permits to have connection that automatically die at a given
time.
Signed-off-by: Eric Leblond <eric@inl.fr>
Signed-off-by: Patrick McHardy <kaber@trash.net>
---
commit fc38099c5c54d23c8cee06ba1b1450f58b5ca1c2
tree 989d91b694430d2bde828a00d81847950108d89a
parent 951256425de86a32569c787ff827554314026824
author Eric Leblond <eric@inl.fr> Tue, 30 May 2006 00:02:45 +0200
committer Patrick McHardy <kaber@trash.net> Tue, 30 May 2006 00:02:45 +0200
include/linux/netfilter/nf_conntrack_common.h | 4 ++++
net/ipv4/netfilter/ip_conntrack_core.c | 6 ++++++
net/netfilter/nf_conntrack_core.c | 6 ++++++
3 files changed, 16 insertions(+), 0 deletions(-)
diff --git a/include/linux/netfilter/nf_conntrack_common.h b/include/linux/netfilter/nf_conntrack_common.h
index 3ff88c8..d2e4bd7 100644
--- a/include/linux/netfilter/nf_conntrack_common.h
+++ b/include/linux/netfilter/nf_conntrack_common.h
@@ -69,6 +69,10 @@ enum ip_conntrack_status {
/* Connection is dying (removed from lists), can not be unset. */
IPS_DYING_BIT = 9,
IPS_DYING = (1 << IPS_DYING_BIT),
+
+ /* Connection has fixed timeout. */
+ IPS_FIXED_TIMEOUT_BIT = 10,
+ IPS_FIXED_TIMEOUT = (1 << IPS_FIXED_TIMEOUT_BIT),
};
/* Connection tracking event bits */
diff --git a/net/ipv4/netfilter/ip_conntrack_core.c b/net/ipv4/netfilter/ip_conntrack_core.c
index 979a2ea..9f0d6ce 100644
--- a/net/ipv4/netfilter/ip_conntrack_core.c
+++ b/net/ipv4/netfilter/ip_conntrack_core.c
@@ -1130,6 +1130,12 @@ void __ip_ct_refresh_acct(struct ip_conn
write_lock_bh(&ip_conntrack_lock);
+ /* Only update if this is not a fixed timeout */
+ if (test_bit(IPS_FIXED_TIMEOUT_BIT, &ct->status)) {
+ write_unlock_bh(&ip_conntrack_lock);
+ return;
+ }
+
/* If not in hash table, timer will not be active yet */
if (!is_confirmed(ct)) {
ct->timeout.expires = extra_jiffies;
diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c
index f9b83f9..bc2bd4c 100644
--- a/net/netfilter/nf_conntrack_core.c
+++ b/net/netfilter/nf_conntrack_core.c
@@ -1396,6 +1396,12 @@ void __nf_ct_refresh_acct(struct nf_conn
write_lock_bh(&nf_conntrack_lock);
+ /* Only update if this is not a fixed timeout */
+ if (test_bit(IPS_FIXED_TIMEOUT_BIT, &ct->status)) {
+ write_unlock_bh(&nf_conntrack_lock);
+ return;
+ }
+
/* If not in hash table, timer will not be active yet */
if (!nf_ct_is_confirmed(ct)) {
ct->timeout.expires = extra_jiffies;
^ permalink raw reply related [flat|nested] 23+ messages in thread* [NETFILTER 09/17]: ctnetlink: fix NAT configuration
2006-05-29 22:34 [NETFILTER 00/17]: Netfilter update for 2.6.18 Patrick McHardy
` (7 preceding siblings ...)
2006-05-29 22:34 ` [NETFILTER 08/17]: conntrack: add fixed timeout flag in connection tracking Patrick McHardy
@ 2006-05-29 22:34 ` Patrick McHardy
2006-05-29 22:34 ` [NETFILTER 10/17]: ctnetlink: change table dumping not to require an unique ID Patrick McHardy
` (8 subsequent siblings)
17 siblings, 0 replies; 23+ messages in thread
From: Patrick McHardy @ 2006-05-29 22:34 UTC (permalink / raw)
To: davem; +Cc: netfilter-devel, Patrick McHardy
[NETFILTER]: ctnetlink: fix NAT configuration
The current configuration only allows to configure one manip and overloads
conntrack status flags with netlink semantic.
Signed-off-by: Patrick Mchardy <kaber@trash.net>
---
commit 614914402a6a25f37b4cc0840e29aa1808d3426e
tree 9f1263181e20728bda8ac1fb2f8a6185c8c4aaa7
parent fc38099c5c54d23c8cee06ba1b1450f58b5ca1c2
author Patrick McHardy <kaber@trash.net> Tue, 30 May 2006 00:04:15 +0200
committer Patrick McHardy <kaber@trash.net> Tue, 30 May 2006 00:04:15 +0200
include/linux/netfilter/nfnetlink_conntrack.h | 4 +-
net/ipv4/netfilter/ip_conntrack_netlink.c | 53 ++++++++++---------------
net/netfilter/nf_conntrack_netlink.c | 53 ++++++++++---------------
3 files changed, 47 insertions(+), 63 deletions(-)
diff --git a/include/linux/netfilter/nfnetlink_conntrack.h b/include/linux/netfilter/nfnetlink_conntrack.h
index 668ec94..b5883cc 100644
--- a/include/linux/netfilter/nfnetlink_conntrack.h
+++ b/include/linux/netfilter/nfnetlink_conntrack.h
@@ -27,13 +27,15 @@ enum ctattr_type {
CTA_STATUS,
CTA_PROTOINFO,
CTA_HELP,
- CTA_NAT,
+ CTA_NAT_SRC,
+#define CTA_NAT CTA_NAT_SRC /* backwards compatibility */
CTA_TIMEOUT,
CTA_MARK,
CTA_COUNTERS_ORIG,
CTA_COUNTERS_REPLY,
CTA_USE,
CTA_ID,
+ CTA_NAT_DST,
__CTA_MAX
};
#define CTA_MAX (__CTA_MAX - 1)
diff --git a/net/ipv4/netfilter/ip_conntrack_netlink.c b/net/ipv4/netfilter/ip_conntrack_netlink.c
index 01bd7ca..af152e3 100644
--- a/net/ipv4/netfilter/ip_conntrack_netlink.c
+++ b/net/ipv4/netfilter/ip_conntrack_netlink.c
@@ -629,7 +629,7 @@ static const size_t cta_min_nat[CTA_NAT_
};
static inline int
-ctnetlink_parse_nat(struct nfattr *cda[],
+ctnetlink_parse_nat(struct nfattr *nat,
const struct ip_conntrack *ct, struct ip_nat_range *range)
{
struct nfattr *tb[CTA_NAT_MAX];
@@ -639,7 +639,7 @@ ctnetlink_parse_nat(struct nfattr *cda[]
memset(range, 0, sizeof(*range));
- nfattr_parse_nested(tb, CTA_NAT_MAX, cda[CTA_NAT-1]);
+ nfattr_parse_nested(tb, CTA_NAT_MAX, nat);
if (nfattr_bad_size(tb, CTA_NAT_MAX, cta_min_nat))
return -EINVAL;
@@ -854,39 +854,30 @@ ctnetlink_change_status(struct ip_conntr
/* ASSURED bit can only be set */
return -EINVAL;
- if (cda[CTA_NAT-1]) {
+ if (cda[CTA_NAT_SRC-1] || cda[CTA_NAT_DST-1]) {
#ifndef CONFIG_IP_NF_NAT_NEEDED
return -EINVAL;
#else
- unsigned int hooknum;
struct ip_nat_range range;
- if (ctnetlink_parse_nat(cda, ct, &range) < 0)
- return -EINVAL;
-
- DEBUGP("NAT: %u.%u.%u.%u-%u.%u.%u.%u:%u-%u\n",
- NIPQUAD(range.min_ip), NIPQUAD(range.max_ip),
- htons(range.min.all), htons(range.max.all));
-
- /* This is tricky but it works. ip_nat_setup_info needs the
- * hook number as parameter, so let's do the correct
- * conversion and run away */
- if (status & IPS_SRC_NAT_DONE)
- hooknum = NF_IP_POST_ROUTING; /* IP_NAT_MANIP_SRC */
- else if (status & IPS_DST_NAT_DONE)
- hooknum = NF_IP_PRE_ROUTING; /* IP_NAT_MANIP_DST */
- else
- return -EINVAL; /* Missing NAT flags */
-
- DEBUGP("NAT status: %lu\n",
- status & (IPS_NAT_MASK | IPS_NAT_DONE_MASK));
-
- if (ip_nat_initialized(ct, HOOK2MANIP(hooknum)))
- return -EEXIST;
- ip_nat_setup_info(ct, &range, hooknum);
-
- DEBUGP("NAT status after setup_info: %lu\n",
- ct->status & (IPS_NAT_MASK | IPS_NAT_DONE_MASK));
+ if (cda[CTA_NAT_DST-1]) {
+ if (ctnetlink_parse_nat(cda[CTA_NAT_DST-1], ct,
+ &range) < 0)
+ return -EINVAL;
+ if (ip_nat_initialized(ct,
+ HOOK2MANIP(NF_IP_PRE_ROUTING)))
+ return -EEXIST;
+ ip_nat_setup_info(ct, &range, NF_IP_PRE_ROUTING);
+ }
+ if (cda[CTA_NAT_SRC-1]) {
+ if (ctnetlink_parse_nat(cda[CTA_NAT_SRC-1], ct,
+ &range) < 0)
+ return -EINVAL;
+ if (ip_nat_initialized(ct,
+ HOOK2MANIP(NF_IP_POST_ROUTING)))
+ return -EEXIST;
+ ip_nat_setup_info(ct, &range, NF_IP_POST_ROUTING);
+ }
#endif
}
@@ -1106,7 +1097,7 @@ ctnetlink_new_conntrack(struct sock *ctn
/* implicit 'else' */
/* we only allow nat config for new conntracks */
- if (cda[CTA_NAT-1]) {
+ if (cda[CTA_NAT_SRC-1] || cda[CTA_NAT_DST-1]) {
err = -EINVAL;
goto out_unlock;
}
diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c
index bd10eb9..8f27fe9 100644
--- a/net/netfilter/nf_conntrack_netlink.c
+++ b/net/netfilter/nf_conntrack_netlink.c
@@ -641,7 +641,7 @@ static const size_t cta_min_nat[CTA_NAT_
};
static inline int
-ctnetlink_parse_nat(struct nfattr *cda[],
+ctnetlink_parse_nat(struct nfattr *nat,
const struct nf_conn *ct, struct ip_nat_range *range)
{
struct nfattr *tb[CTA_NAT_MAX];
@@ -651,7 +651,7 @@ ctnetlink_parse_nat(struct nfattr *cda[]
memset(range, 0, sizeof(*range));
- nfattr_parse_nested(tb, CTA_NAT_MAX, cda[CTA_NAT-1]);
+ nfattr_parse_nested(tb, CTA_NAT_MAX, nat);
if (nfattr_bad_size(tb, CTA_NAT_MAX, cta_min_nat))
return -EINVAL;
@@ -866,39 +866,30 @@ ctnetlink_change_status(struct nf_conn *
/* ASSURED bit can only be set */
return -EINVAL;
- if (cda[CTA_NAT-1]) {
+ if (cda[CTA_NAT_SRC-1] || cda[CTA_NAT_DST-1]) {
#ifndef CONFIG_IP_NF_NAT_NEEDED
return -EINVAL;
#else
- unsigned int hooknum;
struct ip_nat_range range;
- if (ctnetlink_parse_nat(cda, ct, &range) < 0)
- return -EINVAL;
-
- DEBUGP("NAT: %u.%u.%u.%u-%u.%u.%u.%u:%u-%u\n",
- NIPQUAD(range.min_ip), NIPQUAD(range.max_ip),
- htons(range.min.all), htons(range.max.all));
-
- /* This is tricky but it works. ip_nat_setup_info needs the
- * hook number as parameter, so let's do the correct
- * conversion and run away */
- if (status & IPS_SRC_NAT_DONE)
- hooknum = NF_IP_POST_ROUTING; /* IP_NAT_MANIP_SRC */
- else if (status & IPS_DST_NAT_DONE)
- hooknum = NF_IP_PRE_ROUTING; /* IP_NAT_MANIP_DST */
- else
- return -EINVAL; /* Missing NAT flags */
-
- DEBUGP("NAT status: %lu\n",
- status & (IPS_NAT_MASK | IPS_NAT_DONE_MASK));
-
- if (ip_nat_initialized(ct, HOOK2MANIP(hooknum)))
- return -EEXIST;
- ip_nat_setup_info(ct, &range, hooknum);
-
- DEBUGP("NAT status after setup_info: %lu\n",
- ct->status & (IPS_NAT_MASK | IPS_NAT_DONE_MASK));
+ if (cda[CTA_NAT_DST-1]) {
+ if (ctnetlink_parse_nat(cda[CTA_NAT_DST-1], ct,
+ &range) < 0)
+ return -EINVAL;
+ if (ip_nat_initialized(ct,
+ HOOK2MANIP(NF_IP_PRE_ROUTING)))
+ return -EEXIST;
+ ip_nat_setup_info(ct, &range, hooknum);
+ }
+ if (cda[CTA_NAT_SRC-1]) {
+ if (ctnetlink_parse_nat(cda[CTA_NAT_SRC-1], ct,
+ &range) < 0)
+ return -EINVAL;
+ if (ip_nat_initialized(ct,
+ HOOK2MANIP(NF_IP_POST_ROUTING)))
+ return -EEXIST;
+ ip_nat_setup_info(ct, &range, hooknum);
+ }
#endif
}
@@ -1122,7 +1113,7 @@ ctnetlink_new_conntrack(struct sock *ctn
/* implicit 'else' */
/* we only allow nat config for new conntracks */
- if (cda[CTA_NAT-1]) {
+ if (cda[CTA_NAT_SRC-1] || cda[CTA_NAT_DST-1]) {
err = -EINVAL;
goto out_unlock;
}
^ permalink raw reply related [flat|nested] 23+ messages in thread* [NETFILTER 10/17]: ctnetlink: change table dumping not to require an unique ID
2006-05-29 22:34 [NETFILTER 00/17]: Netfilter update for 2.6.18 Patrick McHardy
` (8 preceding siblings ...)
2006-05-29 22:34 ` [NETFILTER 09/17]: ctnetlink: fix NAT configuration Patrick McHardy
@ 2006-05-29 22:34 ` Patrick McHardy
2006-05-29 22:34 ` [NETFILTER 11/17]: SNMP helper: fix debug module param type Patrick McHardy
` (7 subsequent siblings)
17 siblings, 0 replies; 23+ messages in thread
From: Patrick McHardy @ 2006-05-29 22:34 UTC (permalink / raw)
To: davem; +Cc: netfilter-devel, Patrick McHardy
[NETFILTER]: ctnetlink: change table dumping not to require an unique ID
Instead of using the ID to find out where to continue dumping, take a
reference to the last entry dumped and try to continue there.
Signed-off-by: Patrick McHardy <kaber@trash.net>
---
commit 33f076517f429291fcd71b128d3f14b141e3cbdc
tree c6a25b377807ac039ce5290692778b04f7df78c6
parent 614914402a6a25f37b4cc0840e29aa1808d3426e
author Patrick McHardy <kaber@trash.net> Tue, 30 May 2006 00:04:33 +0200
committer Patrick McHardy <kaber@trash.net> Tue, 30 May 2006 00:04:33 +0200
net/ipv4/netfilter/ip_conntrack_netlink.c | 32 ++++++++++++++++++++++-------
net/netfilter/nf_conntrack_netlink.c | 32 ++++++++++++++++++++++-------
2 files changed, 48 insertions(+), 16 deletions(-)
diff --git a/net/ipv4/netfilter/ip_conntrack_netlink.c b/net/ipv4/netfilter/ip_conntrack_netlink.c
index af152e3..33891bb 100644
--- a/net/ipv4/netfilter/ip_conntrack_netlink.c
+++ b/net/ipv4/netfilter/ip_conntrack_netlink.c
@@ -399,38 +399,54 @@ #endif /* CONFIG_IP_NF_CONNTRACK_EVENTS
static int ctnetlink_done(struct netlink_callback *cb)
{
DEBUGP("entered %s\n", __FUNCTION__);
+ if (cb->args[1])
+ ip_conntrack_put((struct ip_conntrack *)cb->args[1]);
return 0;
}
static int
ctnetlink_dump_table(struct sk_buff *skb, struct netlink_callback *cb)
{
- struct ip_conntrack *ct = NULL;
+ struct ip_conntrack *ct, *last;
struct ip_conntrack_tuple_hash *h;
struct list_head *i;
- u_int32_t *id = (u_int32_t *) &cb->args[1];
DEBUGP("entered %s, last bucket=%lu id=%u\n", __FUNCTION__,
cb->args[0], *id);
read_lock_bh(&ip_conntrack_lock);
- for (; cb->args[0] < ip_conntrack_htable_size; cb->args[0]++, *id = 0) {
+ for (; cb->args[0] < ip_conntrack_htable_size; cb->args[0]++) {
+restart:
+ last = (struct ip_conntrack *)cb->args[1];
list_for_each_prev(i, &ip_conntrack_hash[cb->args[0]]) {
h = (struct ip_conntrack_tuple_hash *) i;
if (DIRECTION(h) != IP_CT_DIR_ORIGINAL)
continue;
ct = tuplehash_to_ctrack(h);
- if (ct->id <= *id)
- continue;
+ if (last != NULL) {
+ if (ct == last) {
+ ip_conntrack_put(last);
+ cb->args[1] = 0;
+ last = NULL;
+ } else
+ continue;
+ }
if (ctnetlink_fill_info(skb, NETLINK_CB(cb->skb).pid,
cb->nlh->nlmsg_seq,
IPCTNL_MSG_CT_NEW,
- 1, ct) < 0)
+ 1, ct) < 0) {
+ nf_conntrack_get(&ct->ct_general);
+ cb->args[1] = (unsigned long)ct;
goto out;
- *id = ct->id;
+ }
+ }
+ if (last != NULL) {
+ ip_conntrack_put(last);
+ cb->args[1] = 0;
+ goto restart;
}
}
-out:
+out:
read_unlock_bh(&ip_conntrack_lock);
DEBUGP("leaving, last bucket=%lu id=%u\n", cb->args[0], *id);
diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c
index 8f27fe9..b8c7c56 100644
--- a/net/netfilter/nf_conntrack_netlink.c
+++ b/net/netfilter/nf_conntrack_netlink.c
@@ -407,6 +407,8 @@ #endif /* CONFIG_NF_CONNTRACK_EVENTS */
static int ctnetlink_done(struct netlink_callback *cb)
{
+ if (cb->args[1])
+ nf_ct_put((struct nf_conn *)cb->args[1]);
DEBUGP("entered %s\n", __FUNCTION__);
return 0;
}
@@ -416,10 +418,9 @@ #define L3PROTO(ct) ct->tuplehash[IP_CT_
static int
ctnetlink_dump_table(struct sk_buff *skb, struct netlink_callback *cb)
{
- struct nf_conn *ct = NULL;
+ struct nf_conn *ct, *last;
struct nf_conntrack_tuple_hash *h;
struct list_head *i;
- u_int32_t *id = (u_int32_t *) &cb->args[1];
struct nfgenmsg *nfmsg = NLMSG_DATA(cb->nlh);
u_int8_t l3proto = nfmsg->nfgen_family;
@@ -427,7 +428,9 @@ ctnetlink_dump_table(struct sk_buff *skb
cb->args[0], *id);
read_lock_bh(&nf_conntrack_lock);
- for (; cb->args[0] < nf_conntrack_htable_size; cb->args[0]++, *id = 0) {
+ for (; cb->args[0] < nf_conntrack_htable_size; cb->args[0]++) {
+restart:
+ last = (struct nf_conn *)cb->args[1];
list_for_each_prev(i, &nf_conntrack_hash[cb->args[0]]) {
h = (struct nf_conntrack_tuple_hash *) i;
if (DIRECTION(h) != IP_CT_DIR_ORIGINAL)
@@ -438,17 +441,30 @@ ctnetlink_dump_table(struct sk_buff *skb
* then dump everything. */
if (l3proto && L3PROTO(ct) != l3proto)
continue;
- if (ct->id <= *id)
- continue;
+ if (last != NULL) {
+ if (ct == last) {
+ nf_ct_put(last);
+ cb->args[1] = 0;
+ last = NULL;
+ } else
+ continue;
+ }
if (ctnetlink_fill_info(skb, NETLINK_CB(cb->skb).pid,
cb->nlh->nlmsg_seq,
IPCTNL_MSG_CT_NEW,
- 1, ct) < 0)
+ 1, ct) < 0) {
+ nf_conntrack_get(&ct->ct_general);
+ cb->args[1] = (unsigned long)ct;
goto out;
- *id = ct->id;
+ }
+ }
+ if (last != NULL) {
+ nf_ct_put(last);
+ cb->args[1] = 0;
+ goto restart;
}
}
-out:
+out:
read_unlock_bh(&nf_conntrack_lock);
DEBUGP("leaving, last bucket=%lu id=%u\n", cb->args[0], *id);
^ permalink raw reply related [flat|nested] 23+ messages in thread* [NETFILTER 11/17]: SNMP helper: fix debug module param type
2006-05-29 22:34 [NETFILTER 00/17]: Netfilter update for 2.6.18 Patrick McHardy
` (9 preceding siblings ...)
2006-05-29 22:34 ` [NETFILTER 10/17]: ctnetlink: change table dumping not to require an unique ID Patrick McHardy
@ 2006-05-29 22:34 ` Patrick McHardy
2006-05-29 22:34 ` [NETFILTER 12/17]: FTP helper: search optimization Patrick McHardy
` (6 subsequent siblings)
17 siblings, 0 replies; 23+ messages in thread
From: Patrick McHardy @ 2006-05-29 22:34 UTC (permalink / raw)
To: davem; +Cc: netfilter-devel, Patrick McHardy
[NETFILTER]: SNMP helper: fix debug module param type
debug is the debug level, not a bool.
Signed-off-by: Patrick McHardy <kaber@trash.net>
---
commit 1782413b89b52410a4df654860145bc2a27db194
tree c7d0a7dea3b9a8b9260cc0500bfe702b62254de8
parent 33f076517f429291fcd71b128d3f14b141e3cbdc
author Patrick McHardy <kaber@trash.net> Tue, 30 May 2006 00:04:34 +0200
committer Patrick McHardy <kaber@trash.net> Tue, 30 May 2006 00:04:34 +0200
net/ipv4/netfilter/ip_nat_snmp_basic.c | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/net/ipv4/netfilter/ip_nat_snmp_basic.c b/net/ipv4/netfilter/ip_nat_snmp_basic.c
index c332442..d20d557 100644
--- a/net/ipv4/netfilter/ip_nat_snmp_basic.c
+++ b/net/ipv4/netfilter/ip_nat_snmp_basic.c
@@ -1348,4 +1348,4 @@ static void __exit ip_nat_snmp_basic_fin
module_init(ip_nat_snmp_basic_init);
module_exit(ip_nat_snmp_basic_fini);
-module_param(debug, bool, 0600);
+module_param(debug, int, 0600);
^ permalink raw reply related [flat|nested] 23+ messages in thread* [NETFILTER 12/17]: FTP helper: search optimization
2006-05-29 22:34 [NETFILTER 00/17]: Netfilter update for 2.6.18 Patrick McHardy
` (10 preceding siblings ...)
2006-05-29 22:34 ` [NETFILTER 11/17]: SNMP helper: fix debug module param type Patrick McHardy
@ 2006-05-29 22:34 ` Patrick McHardy
2006-05-29 22:34 ` [NETFILTER 13/17]: amanda helper: convert to textsearch infrastructure Patrick McHardy
` (5 subsequent siblings)
17 siblings, 0 replies; 23+ messages in thread
From: Patrick McHardy @ 2006-05-29 22:34 UTC (permalink / raw)
To: davem; +Cc: netfilter-devel, Patrick McHardy
[NETFILTER]: FTP helper: search optimization
Instead of skipping search entries for the wrong direction simply index
them by direction.
Based on patch by Pablo Neira <pablo@netfilter.org>
Signed-off-by: Patrick McHardy <kaber@trash.net>
---
commit 782e3aa01e036825fcfc353952d5585a02eb946a
tree 3779723e9d6f995a75582dbde1fd82e37986ef4b
parent 1782413b89b52410a4df654860145bc2a27db194
author Patrick McHardy <kaber@trash.net> Tue, 30 May 2006 00:04:35 +0200
committer Patrick McHardy <kaber@trash.net> Tue, 30 May 2006 00:04:35 +0200
net/ipv4/netfilter/ip_conntrack_ftp.c | 77 ++++++++++++++++++---------------
net/netfilter/nf_conntrack_ftp.c | 77 ++++++++++++++++++---------------
2 files changed, 86 insertions(+), 68 deletions(-)
diff --git a/net/ipv4/netfilter/ip_conntrack_ftp.c b/net/ipv4/netfilter/ip_conntrack_ftp.c
index 3e542bf..4dcf526 100644
--- a/net/ipv4/netfilter/ip_conntrack_ftp.c
+++ b/net/ipv4/netfilter/ip_conntrack_ftp.c
@@ -56,37 +56,48 @@ static int try_eprt(const char *, size_t
static int try_epsv_response(const char *, size_t, u_int32_t [], char);
static const struct ftp_search {
- enum ip_conntrack_dir dir;
const char *pattern;
size_t plen;
char skip;
char term;
enum ip_ct_ftp_type ftptype;
int (*getnum)(const char *, size_t, u_int32_t[], char);
-} search[] = {
- {
- IP_CT_DIR_ORIGINAL,
- "PORT", sizeof("PORT") - 1, ' ', '\r',
- IP_CT_FTP_PORT,
- try_rfc959,
+} search[IP_CT_DIR_MAX][2] = {
+ [IP_CT_DIR_ORIGINAL] = {
+ {
+ .pattern = "PORT",
+ .plen = sizeof("PORT") - 1,
+ .skip = ' ',
+ .term = '\r',
+ .ftptype = IP_CT_FTP_PORT,
+ .getnum = try_rfc959,
+ },
+ {
+ .pattern = "EPRT",
+ .plen = sizeof("EPRT") - 1,
+ .skip = ' ',
+ .term = '\r',
+ .ftptype = IP_CT_FTP_EPRT,
+ .getnum = try_eprt,
+ },
},
- {
- IP_CT_DIR_REPLY,
- "227 ", sizeof("227 ") - 1, '(', ')',
- IP_CT_FTP_PASV,
- try_rfc959,
- },
- {
- IP_CT_DIR_ORIGINAL,
- "EPRT", sizeof("EPRT") - 1, ' ', '\r',
- IP_CT_FTP_EPRT,
- try_eprt,
- },
- {
- IP_CT_DIR_REPLY,
- "229 ", sizeof("229 ") - 1, '(', ')',
- IP_CT_FTP_EPSV,
- try_epsv_response,
+ [IP_CT_DIR_REPLY] = {
+ {
+ .pattern = "227 ",
+ .plen = sizeof("227 ") - 1,
+ .skip = '(',
+ .term = ')',
+ .ftptype = IP_CT_FTP_PASV,
+ .getnum = try_rfc959,
+ },
+ {
+ .pattern = "229 ",
+ .plen = sizeof("229 ") - 1,
+ .skip = '(',
+ .term = ')',
+ .ftptype = IP_CT_FTP_EPSV,
+ .getnum = try_epsv_response,
+ },
},
};
@@ -346,17 +357,15 @@ static int help(struct sk_buff **pskb,
array[2] = (ntohl(ct->tuplehash[dir].tuple.src.ip) >> 8) & 0xFF;
array[3] = ntohl(ct->tuplehash[dir].tuple.src.ip) & 0xFF;
- for (i = 0; i < ARRAY_SIZE(search); i++) {
- if (search[i].dir != dir) continue;
-
+ for (i = 0; i < ARRAY_SIZE(search[dir]); i++) {
found = find_pattern(fb_ptr, (*pskb)->len - dataoff,
- search[i].pattern,
- search[i].plen,
- search[i].skip,
- search[i].term,
+ search[dir][i].pattern,
+ search[dir][i].plen,
+ search[dir][i].skip,
+ search[dir][i].term,
&matchoff, &matchlen,
array,
- search[i].getnum);
+ search[dir][i].getnum);
if (found) break;
}
if (found == -1) {
@@ -366,7 +375,7 @@ static int help(struct sk_buff **pskb,
this case. */
if (net_ratelimit())
printk("conntrack_ftp: partial %s %u+%u\n",
- search[i].pattern,
+ search[dir][i].pattern,
ntohl(th->seq), datalen);
ret = NF_DROP;
goto out;
@@ -426,7 +435,7 @@ static int help(struct sk_buff **pskb,
/* Now, NAT might want to mangle the packet, and register the
* (possibly changed) expectation itself. */
if (ip_nat_ftp_hook)
- ret = ip_nat_ftp_hook(pskb, ctinfo, search[i].ftptype,
+ ret = ip_nat_ftp_hook(pskb, ctinfo, search[dir][i].ftptype,
matchoff, matchlen, exp, &seq);
else {
/* Can't expect this? Best to drop packet now. */
diff --git a/net/netfilter/nf_conntrack_ftp.c b/net/netfilter/nf_conntrack_ftp.c
index e38a4b5..11d3be2 100644
--- a/net/netfilter/nf_conntrack_ftp.c
+++ b/net/netfilter/nf_conntrack_ftp.c
@@ -67,37 +67,48 @@ static int try_epsv_response(const char
char);
static struct ftp_search {
- enum ip_conntrack_dir dir;
const char *pattern;
size_t plen;
char skip;
char term;
enum ip_ct_ftp_type ftptype;
int (*getnum)(const char *, size_t, struct nf_conntrack_man *, char);
-} search[] = {
- {
- IP_CT_DIR_ORIGINAL,
- "PORT", sizeof("PORT") - 1, ' ', '\r',
- IP_CT_FTP_PORT,
- try_rfc959,
+} search[IP_CT_DIR_MAX][2] = {
+ [IP_CT_DIR_ORIGINAL] = {
+ {
+ .pattern = "PORT",
+ .plen = sizeof("PORT") - 1,
+ .skip = ' ',
+ .term = '\r',
+ .ftptype = IP_CT_FTP_PORT,
+ .getnum = try_rfc959,
+ },
+ {
+ .pattern = "EPRT",
+ .plen = sizeof("EPRT") - 1,
+ .skip = ' ',
+ .term = '\r',
+ .ftptype = IP_CT_FTP_EPRT,
+ .getnum = try_eprt,
+ },
},
- {
- IP_CT_DIR_REPLY,
- "227 ", sizeof("227 ") - 1, '(', ')',
- IP_CT_FTP_PASV,
- try_rfc959,
- },
- {
- IP_CT_DIR_ORIGINAL,
- "EPRT", sizeof("EPRT") - 1, ' ', '\r',
- IP_CT_FTP_EPRT,
- try_eprt,
- },
- {
- IP_CT_DIR_REPLY,
- "229 ", sizeof("229 ") - 1, '(', ')',
- IP_CT_FTP_EPSV,
- try_epsv_response,
+ [IP_CT_DIR_REPLY] = {
+ {
+ .pattern = "227 ",
+ .plen = sizeof("227 ") - 1,
+ .skip = '(',
+ .term = ')',
+ .ftptype = IP_CT_FTP_PASV,
+ .getnum = try_rfc959,
+ },
+ {
+ .pattern = "229 ",
+ .plen = sizeof("229 ") - 1,
+ .skip = '(',
+ .term = ')',
+ .ftptype = IP_CT_FTP_EPSV,
+ .getnum = try_epsv_response,
+ },
},
};
@@ -492,17 +503,15 @@ static int help(struct sk_buff **pskb,
memcpy(cmd.u3.all, &ct->tuplehash[dir].tuple.src.u3.all,
sizeof(cmd.u3.all));
- for (i = 0; i < ARRAY_SIZE(search); i++) {
- if (search[i].dir != dir) continue;
-
+ for (i = 0; i < ARRAY_SIZE(search[dir]); i++) {
found = find_pattern(fb_ptr, datalen,
- search[i].pattern,
- search[i].plen,
- search[i].skip,
- search[i].term,
+ search[dir][i].pattern,
+ search[dir][i].plen,
+ search[dir][i].skip,
+ search[dir][i].term,
&matchoff, &matchlen,
&cmd,
- search[i].getnum);
+ search[dir][i].getnum);
if (found) break;
}
if (found == -1) {
@@ -512,7 +521,7 @@ static int help(struct sk_buff **pskb,
this case. */
if (net_ratelimit())
printk("conntrack_ftp: partial %s %u+%u\n",
- search[i].pattern,
+ search[dir][i].pattern,
ntohl(th->seq), datalen);
ret = NF_DROP;
goto out;
@@ -597,7 +606,7 @@ static int help(struct sk_buff **pskb,
/* Now, NAT might want to mangle the packet, and register the
* (possibly changed) expectation itself. */
if (nf_nat_ftp_hook)
- ret = nf_nat_ftp_hook(pskb, ctinfo, search[i].ftptype,
+ ret = nf_nat_ftp_hook(pskb, ctinfo, search[dir][i].ftptype,
matchoff, matchlen, exp, &seq);
else {
/* Can't expect this? Best to drop packet now. */
^ permalink raw reply related [flat|nested] 23+ messages in thread* [NETFILTER 13/17]: amanda helper: convert to textsearch infrastructure
2006-05-29 22:34 [NETFILTER 00/17]: Netfilter update for 2.6.18 Patrick McHardy
` (11 preceding siblings ...)
2006-05-29 22:34 ` [NETFILTER 12/17]: FTP helper: search optimization Patrick McHardy
@ 2006-05-29 22:34 ` Patrick McHardy
2006-05-29 22:34 ` [NETFILTER 14/17]: H.323 helper: Add support for Call Forwarding Patrick McHardy
` (4 subsequent siblings)
17 siblings, 0 replies; 23+ messages in thread
From: Patrick McHardy @ 2006-05-29 22:34 UTC (permalink / raw)
To: davem; +Cc: netfilter-devel, Patrick McHardy
[NETFILTER]: amanda helper: convert to textsearch infrastructure
When a port number within a packet is replaced by a differently sized
number only the packet is resized, but not the copy of the data.
Following port numbers are rewritten based on their offsets within
the copy, leading to packet corruption.
Convert the amanda helper to the textsearch infrastructure to avoid
the copy entirely.
Signed-off-by: Patrick McHardy <kaber@trash.net>
---
commit 66a750bcda3b4d3ed7e7b93e190a464fa5ed4dc6
tree 46e3a8dd2788ff0c0f345e15fee05b9bf966342a
parent 782e3aa01e036825fcfc353952d5585a02eb946a
author Patrick McHardy <kaber@trash.net> Tue, 30 May 2006 00:08:27 +0200
committer Patrick McHardy <kaber@trash.net> Tue, 30 May 2006 00:08:27 +0200
net/ipv4/netfilter/Kconfig | 2
net/ipv4/netfilter/ip_conntrack_amanda.c | 143 ++++++++++++++++++++----------
2 files changed, 96 insertions(+), 49 deletions(-)
diff --git a/net/ipv4/netfilter/Kconfig b/net/ipv4/netfilter/Kconfig
index 3d560de..d859754 100644
--- a/net/ipv4/netfilter/Kconfig
+++ b/net/ipv4/netfilter/Kconfig
@@ -142,6 +142,8 @@ config IP_NF_TFTP
config IP_NF_AMANDA
tristate "Amanda backup protocol support"
depends on IP_NF_CONNTRACK
+ select TEXTSEARCH
+ select TEXTSEARCH_KMP
help
If you are running the Amanda backup package <http://www.amanda.org/>
on this machine or machines that will be MASQUERADED through this
diff --git a/net/ipv4/netfilter/ip_conntrack_amanda.c b/net/ipv4/netfilter/ip_conntrack_amanda.c
index a604b1c..0a7bd7f 100644
--- a/net/ipv4/netfilter/ip_conntrack_amanda.c
+++ b/net/ipv4/netfilter/ip_conntrack_amanda.c
@@ -17,33 +17,29 @@
* this value.
*
*/
-
-#include <linux/in.h>
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/netfilter.h>
-#include <linux/ip.h>
#include <linux/moduleparam.h>
+#include <linux/textsearch.h>
+#include <linux/skbuff.h>
+#include <linux/in.h>
+#include <linux/ip.h>
#include <linux/udp.h>
-#include <net/checksum.h>
-#include <net/udp.h>
+#include <linux/netfilter.h>
#include <linux/netfilter_ipv4/ip_conntrack_helper.h>
#include <linux/netfilter_ipv4/ip_conntrack_amanda.h>
static unsigned int master_timeout = 300;
+static char *ts_algo = "kmp";
MODULE_AUTHOR("Brian J. Murrell <netfilter@interlinx.bc.ca>");
MODULE_DESCRIPTION("Amanda connection tracking module");
MODULE_LICENSE("GPL");
module_param(master_timeout, uint, 0600);
MODULE_PARM_DESC(master_timeout, "timeout for the master connection");
-
-static const char *conns[] = { "DATA ", "MESG ", "INDEX " };
-
-/* This is slow, but it's simple. --RR */
-static char *amanda_buffer;
-static DEFINE_SPINLOCK(amanda_buffer_lock);
+module_param(ts_algo, charp, 0400);
+MODULE_PARM_DESC(ts_algo, "textsearch algorithm to use (default kmp)");
unsigned int (*ip_nat_amanda_hook)(struct sk_buff **pskb,
enum ip_conntrack_info ctinfo,
@@ -52,12 +48,48 @@ unsigned int (*ip_nat_amanda_hook)(struc
struct ip_conntrack_expect *exp);
EXPORT_SYMBOL_GPL(ip_nat_amanda_hook);
+enum amanda_strings {
+ SEARCH_CONNECT,
+ SEARCH_NEWLINE,
+ SEARCH_DATA,
+ SEARCH_MESG,
+ SEARCH_INDEX,
+};
+
+static struct {
+ char *string;
+ size_t len;
+ struct ts_config *ts;
+} search[] = {
+ [SEARCH_CONNECT] = {
+ .string = "CONNECT ",
+ .len = 8,
+ },
+ [SEARCH_NEWLINE] = {
+ .string = "\n",
+ .len = 1,
+ },
+ [SEARCH_DATA] = {
+ .string = "DATA ",
+ .len = 5,
+ },
+ [SEARCH_MESG] = {
+ .string = "MESG ",
+ .len = 5,
+ },
+ [SEARCH_INDEX] = {
+ .string = "INDEX ",
+ .len = 6,
+ },
+};
+
static int help(struct sk_buff **pskb,
struct ip_conntrack *ct, enum ip_conntrack_info ctinfo)
{
+ struct ts_state ts;
struct ip_conntrack_expect *exp;
- char *data, *data_limit, *tmp;
- unsigned int dataoff, i;
+ unsigned int dataoff, start, stop, off, i;
+ char pbuf[sizeof("65535")], *tmp;
u_int16_t port, len;
int ret = NF_ACCEPT;
@@ -77,29 +109,34 @@ static int help(struct sk_buff **pskb,
return NF_ACCEPT;
}
- spin_lock_bh(&amanda_buffer_lock);
- skb_copy_bits(*pskb, dataoff, amanda_buffer, (*pskb)->len - dataoff);
- data = amanda_buffer;
- data_limit = amanda_buffer + (*pskb)->len - dataoff;
- *data_limit = '\0';
-
- /* Search for the CONNECT string */
- data = strstr(data, "CONNECT ");
- if (!data)
+ memset(&ts, 0, sizeof(ts));
+ start = skb_find_text(*pskb, dataoff, (*pskb)->len,
+ search[SEARCH_CONNECT].ts, &ts);
+ if (start == UINT_MAX)
goto out;
- data += strlen("CONNECT ");
+ start += dataoff + search[SEARCH_CONNECT].len;
- /* Only search first line. */
- if ((tmp = strchr(data, '\n')))
- *tmp = '\0';
+ memset(&ts, 0, sizeof(ts));
+ stop = skb_find_text(*pskb, start, (*pskb)->len,
+ search[SEARCH_NEWLINE].ts, &ts);
+ if (stop == UINT_MAX)
+ goto out;
+ stop += start;
- for (i = 0; i < ARRAY_SIZE(conns); i++) {
- char *match = strstr(data, conns[i]);
- if (!match)
+ for (i = SEARCH_DATA; i <= SEARCH_INDEX; i++) {
+ memset(&ts, 0, sizeof(ts));
+ off = skb_find_text(*pskb, start, stop, search[i].ts, &ts);
+ if (off == UINT_MAX)
continue;
- tmp = data = match + strlen(conns[i]);
- port = simple_strtoul(data, &data, 10);
- len = data - tmp;
+ off += start + search[i].len;
+
+ len = min_t(unsigned int, sizeof(pbuf) - 1, stop - off);
+ if (skb_copy_bits(*pskb, off, pbuf, len))
+ break;
+ pbuf[len] = '\0';
+
+ port = simple_strtoul(pbuf, &tmp, 10);
+ len = tmp - pbuf;
if (port == 0 || len > 5)
break;
@@ -125,8 +162,7 @@ static int help(struct sk_buff **pskb,
exp->mask.dst.u.tcp.port = 0xFFFF;
if (ip_nat_amanda_hook)
- ret = ip_nat_amanda_hook(pskb, ctinfo,
- tmp - amanda_buffer,
+ ret = ip_nat_amanda_hook(pskb, ctinfo, off - dataoff,
len, exp);
else if (ip_conntrack_expect_related(exp) != 0)
ret = NF_DROP;
@@ -134,12 +170,11 @@ static int help(struct sk_buff **pskb,
}
out:
- spin_unlock_bh(&amanda_buffer_lock);
return ret;
}
static struct ip_conntrack_helper amanda_helper = {
- .max_expected = ARRAY_SIZE(conns),
+ .max_expected = 3,
.timeout = 180,
.me = THIS_MODULE,
.help = help,
@@ -155,26 +190,36 @@ static struct ip_conntrack_helper amanda
static void __exit ip_conntrack_amanda_fini(void)
{
+ int i;
+
ip_conntrack_helper_unregister(&amanda_helper);
- kfree(amanda_buffer);
+ for (i = 0; i < ARRAY_SIZE(search); i++)
+ textsearch_destroy(search[i].ts);
}
static int __init ip_conntrack_amanda_init(void)
{
- int ret;
-
- amanda_buffer = kmalloc(65536, GFP_KERNEL);
- if (!amanda_buffer)
- return -ENOMEM;
-
- ret = ip_conntrack_helper_register(&amanda_helper);
- if (ret < 0) {
- kfree(amanda_buffer);
- return ret;
+ int ret, i;
+
+ ret = -ENOMEM;
+ for (i = 0; i < ARRAY_SIZE(search); i++) {
+ search[i].ts = textsearch_prepare(ts_algo, search[i].string,
+ search[i].len,
+ GFP_KERNEL, TS_AUTOLOAD);
+ if (search[i].ts == NULL)
+ goto err;
}
+ ret = ip_conntrack_helper_register(&amanda_helper);
+ if (ret < 0)
+ goto err;
return 0;
-
+err:
+ for (; i >= 0; i--) {
+ if (search[i].ts)
+ textsearch_destroy(search[i].ts);
+ }
+ return ret;
}
module_init(ip_conntrack_amanda_init);
^ permalink raw reply related [flat|nested] 23+ messages in thread* [NETFILTER 14/17]: H.323 helper: Add support for Call Forwarding
2006-05-29 22:34 [NETFILTER 00/17]: Netfilter update for 2.6.18 Patrick McHardy
` (12 preceding siblings ...)
2006-05-29 22:34 ` [NETFILTER 13/17]: amanda helper: convert to textsearch infrastructure Patrick McHardy
@ 2006-05-29 22:34 ` Patrick McHardy
2006-05-29 22:34 ` [NETFILTER 15/17]: H.323 helper: replace internal_net_addr parameter by routing-based heuristic Patrick McHardy
` (3 subsequent siblings)
17 siblings, 0 replies; 23+ messages in thread
From: Patrick McHardy @ 2006-05-29 22:34 UTC (permalink / raw)
To: davem; +Cc: netfilter-devel, Patrick McHardy
[NETFILTER]: H.323 helper: Add support for Call Forwarding
Signed-off-by: Jing Min Zhao <zhaojingmin@users.sourceforge.net>
Signed-off-by: Patrick McHardy <kaber@trash.net>
---
commit cf55d393a491b6d441f36a68117e9bdfc8940a47
tree be84c8954b69c46594597c9fb2a63b0b4bf778b4
parent 66a750bcda3b4d3ed7e7b93e190a464fa5ed4dc6
author Jing Min Zhao <zhaojingmin@users.sourceforge.net> Tue, 30 May 2006 00:08:44 +0200
committer Patrick McHardy <kaber@trash.net> Tue, 30 May 2006 00:08:44 +0200
include/linux/netfilter_ipv4/ip_conntrack.h | 1
include/linux/netfilter_ipv4/ip_conntrack_h323.h | 7 +
.../ip_conntrack_helper_h323_types.h | 3 -
net/ipv4/netfilter/Kconfig | 8 +
net/ipv4/netfilter/ip_conntrack_helper_h323.c | 112 ++++++++++++++++++++
.../netfilter/ip_conntrack_helper_h323_types.c | 6 +
net/ipv4/netfilter/ip_nat_helper_h323.c | 77 ++++++++++++++
7 files changed, 206 insertions(+), 8 deletions(-)
diff --git a/include/linux/netfilter_ipv4/ip_conntrack.h b/include/linux/netfilter_ipv4/ip_conntrack.h
index 5473c01..17d7ef9 100644
--- a/include/linux/netfilter_ipv4/ip_conntrack.h
+++ b/include/linux/netfilter_ipv4/ip_conntrack.h
@@ -154,6 +154,7 @@ struct ip_conntrack_expect
unsigned int flags;
#ifdef CONFIG_IP_NF_NAT_NEEDED
+ u_int32_t saved_ip;
/* This is the original per-proto part, used to map the
* expected connection the way the recipient expects. */
union ip_conntrack_manip_proto saved_proto;
diff --git a/include/linux/netfilter_ipv4/ip_conntrack_h323.h b/include/linux/netfilter_ipv4/ip_conntrack_h323.h
index eace86b..3cbff73 100644
--- a/include/linux/netfilter_ipv4/ip_conntrack_h323.h
+++ b/include/linux/netfilter_ipv4/ip_conntrack_h323.h
@@ -71,6 +71,13 @@ extern int (*nat_h245_hook) (struct sk_b
unsigned char **data, int dataoff,
TransportAddress * addr, u_int16_t port,
struct ip_conntrack_expect * exp);
+extern int (*nat_callforwarding_hook) (struct sk_buff ** pskb,
+ struct ip_conntrack * ct,
+ enum ip_conntrack_info ctinfo,
+ unsigned char **data, int dataoff,
+ TransportAddress * addr,
+ u_int16_t port,
+ struct ip_conntrack_expect * exp);
extern int (*nat_q931_hook) (struct sk_buff ** pskb, struct ip_conntrack * ct,
enum ip_conntrack_info ctinfo,
unsigned char **data, TransportAddress * addr,
diff --git a/include/linux/netfilter_ipv4/ip_conntrack_helper_h323_types.h b/include/linux/netfilter_ipv4/ip_conntrack_helper_h323_types.h
index cc98f7a..3d4a773 100644
--- a/include/linux/netfilter_ipv4/ip_conntrack_helper_h323_types.h
+++ b/include/linux/netfilter_ipv4/ip_conntrack_helper_h323_types.h
@@ -1,4 +1,4 @@
-/* Generated by Jing Min Zhao's ASN.1 parser, Mar 15 2006
+/* Generated by Jing Min Zhao's ASN.1 parser, Apr 20 2006
*
* Copyright (c) 2006 Jing Min Zhao <zhaojingmin@users.sourceforge.net>
*
@@ -412,6 +412,7 @@ typedef struct Facility_UUIE { /* SEQUEN
eFacility_UUIE_destinationInfo = (1 << 14),
eFacility_UUIE_h245SecurityMode = (1 << 13),
} options;
+ TransportAddress alternativeAddress;
FacilityReason reason;
TransportAddress h245Address;
Facility_UUIE_fastStart fastStart;
diff --git a/net/ipv4/netfilter/Kconfig b/net/ipv4/netfilter/Kconfig
index d859754..fd37223 100644
--- a/net/ipv4/netfilter/Kconfig
+++ b/net/ipv4/netfilter/Kconfig
@@ -183,10 +183,10 @@ config IP_NF_H323
With this module you can support H.323 on a connection tracking/NAT
firewall.
- This module supports RAS, Fast-start, H.245 tunnelling, RTP/RTCP
- and T.120 based data and applications including audio, video, FAX,
- chat, whiteboard, file transfer, etc. For more information, please
- see http://nath323.sourceforge.net/.
+ This module supports RAS, Fast Start, H.245 Tunnelling, Call
+ Forwarding, RTP/RTCP and T.120 based audio, video, fax, chat,
+ whiteboard, file transfer, etc. For more information, please
+ visit http://nath323.sourceforge.net/.
If you want to compile it as a module, say 'M' here and read
Documentation/modules.txt. If unsure, say 'N'.
diff --git a/net/ipv4/netfilter/ip_conntrack_helper_h323.c b/net/ipv4/netfilter/ip_conntrack_helper_h323.c
index 518f581..3052468 100644
--- a/net/ipv4/netfilter/ip_conntrack_helper_h323.c
+++ b/net/ipv4/netfilter/ip_conntrack_helper_h323.c
@@ -22,6 +22,8 @@ #include <linux/netfilter_ipv4/ip_conntr
#include <linux/netfilter_ipv4/ip_conntrack_tuple.h>
#include <linux/netfilter_ipv4/ip_conntrack_h323.h>
#include <linux/moduleparam.h>
+#include <linux/ctype.h>
+#include <linux/inet.h>
#if 0
#define DEBUGP printk
@@ -38,6 +40,13 @@ static int gkrouted_only = 1;
module_param(gkrouted_only, int, 0600);
MODULE_PARM_DESC(gkrouted_only, "only accept calls from gatekeeper");
+static char *internal_net = NULL;
+static u_int32_t internal_net_addr = 0;
+static u_int32_t internal_net_mask = 0;
+module_param(internal_net, charp, 0600);
+MODULE_PARM_DESC(internal_net, "specify your internal network using format "
+ "address/mask. this is used by call forwarding support");
+
/* Hooks for NAT */
int (*set_h245_addr_hook) (struct sk_buff ** pskb,
unsigned char **data, int dataoff,
@@ -77,6 +86,12 @@ int (*nat_h245_hook) (struct sk_buff **
unsigned char **data, int dataoff,
TransportAddress * addr, u_int16_t port,
struct ip_conntrack_expect * exp);
+int (*nat_callforwarding_hook) (struct sk_buff ** pskb,
+ struct ip_conntrack * ct,
+ enum ip_conntrack_info ctinfo,
+ unsigned char **data, int dataoff,
+ TransportAddress * addr, u_int16_t port,
+ struct ip_conntrack_expect * exp);
int (*nat_q931_hook) (struct sk_buff ** pskb,
struct ip_conntrack * ct,
enum ip_conntrack_info ctinfo,
@@ -683,6 +698,76 @@ static int expect_h245(struct sk_buff **
return ret;
}
+/* Forwarding declaration */
+void ip_conntrack_q931_expect(struct ip_conntrack *new,
+ struct ip_conntrack_expect *this);
+
+/****************************************************************************/
+static int expect_callforwarding(struct sk_buff **pskb,
+ struct ip_conntrack *ct,
+ enum ip_conntrack_info ctinfo,
+ unsigned char **data, int dataoff,
+ TransportAddress * addr)
+{
+ int dir = CTINFO2DIR(ctinfo);
+ int ret = 0;
+ u_int32_t ip;
+ u_int16_t port;
+ struct ip_conntrack_expect *exp = NULL;
+
+ /* Read alternativeAddress */
+ if (!get_h225_addr(*data, addr, &ip, &port) || port == 0)
+ return 0;
+
+ /* If the calling party is on the same side of the forward-to party,
+ * we don't need to track the second call */
+ if (internal_net &&
+ ((ip & internal_net_mask) == internal_net_addr) ==
+ ((ct->tuplehash[!dir].tuple.src.ip & internal_net_mask) ==
+ internal_net_addr)) {
+ DEBUGP("ip_ct_q931: Call Forwarding not tracked\n");
+ return 0;
+ }
+
+ /* Create expect for the second call leg */
+ if ((exp = ip_conntrack_expect_alloc(ct)) == NULL)
+ return -1;
+ exp->tuple.src.ip = ct->tuplehash[!dir].tuple.src.ip;
+ exp->tuple.src.u.tcp.port = 0;
+ exp->tuple.dst.ip = ip;
+ exp->tuple.dst.u.tcp.port = htons(port);
+ exp->tuple.dst.protonum = IPPROTO_TCP;
+ exp->mask.src.ip = 0xFFFFFFFF;
+ exp->mask.src.u.tcp.port = 0;
+ exp->mask.dst.ip = 0xFFFFFFFF;
+ exp->mask.dst.u.tcp.port = 0xFFFF;
+ exp->mask.dst.protonum = 0xFF;
+ exp->flags = 0;
+
+ if (ct->tuplehash[dir].tuple.src.ip !=
+ ct->tuplehash[!dir].tuple.dst.ip && nat_callforwarding_hook) {
+ /* Need NAT */
+ ret = nat_callforwarding_hook(pskb, ct, ctinfo, data, dataoff,
+ addr, port, exp);
+ } else { /* Conntrack only */
+ exp->expectfn = ip_conntrack_q931_expect;
+
+ if (ip_conntrack_expect_related(exp) == 0) {
+ DEBUGP("ip_ct_q931: expect Call Forwarding "
+ "%u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n",
+ NIPQUAD(exp->tuple.src.ip),
+ ntohs(exp->tuple.src.u.tcp.port),
+ NIPQUAD(exp->tuple.dst.ip),
+ ntohs(exp->tuple.dst.u.tcp.port));
+ } else
+ ret = -1;
+ }
+
+ ip_conntrack_expect_put(exp);
+
+ return ret;
+}
+
/****************************************************************************/
static int process_setup(struct sk_buff **pskb, struct ip_conntrack *ct,
enum ip_conntrack_info ctinfo,
@@ -878,6 +963,15 @@ static int process_facility(struct sk_bu
DEBUGP("ip_ct_q931: Facility\n");
+ if (facility->reason.choice == eFacilityReason_callForwarded) {
+ if (facility->options & eFacility_UUIE_alternativeAddress)
+ return expect_callforwarding(pskb, ct, ctinfo, data,
+ dataoff,
+ &facility->
+ alternativeAddress);
+ return 0;
+ }
+
if (facility->options & eFacility_UUIE_h245Address) {
ret = expect_h245(pskb, ct, ctinfo, data, dataoff,
&facility->h245Address);
@@ -1668,6 +1762,7 @@ static void fini(void)
static int __init init(void)
{
int ret;
+ char *p;
h323_buffer = kmalloc(65536, GFP_KERNEL);
if (!h323_buffer)
@@ -1678,6 +1773,22 @@ static int __init init(void)
return ret;
}
+ if (internal_net) {
+ if ((p = strchr(internal_net, '/')))
+ *p++ = 0;
+ if (isdigit(internal_net[0])) {
+ internal_net_addr = in_aton(internal_net);
+ if (p && isdigit(p[0]))
+ internal_net_mask = in_aton(p);
+ else
+ internal_net_mask = 0xffffffff;
+ internal_net_addr &= internal_net_mask;
+ }
+ DEBUGP("ip_ct_h323: internal_net = %u.%u.%u.%u/%u.%u.%u.%u\n",
+ NIPQUAD(internal_net_addr),
+ NIPQUAD(internal_net_mask));
+ }
+
DEBUGP("ip_ct_h323: init success\n");
return 0;
}
@@ -1696,6 +1807,7 @@ EXPORT_SYMBOL_GPL(set_ras_addr_hook);
EXPORT_SYMBOL_GPL(nat_rtp_rtcp_hook);
EXPORT_SYMBOL_GPL(nat_t120_hook);
EXPORT_SYMBOL_GPL(nat_h245_hook);
+EXPORT_SYMBOL_GPL(nat_callforwarding_hook);
EXPORT_SYMBOL_GPL(nat_q931_hook);
MODULE_AUTHOR("Jing Min Zhao <zhaojingmin@users.sourceforge.net>");
diff --git a/net/ipv4/netfilter/ip_conntrack_helper_h323_types.c b/net/ipv4/netfilter/ip_conntrack_helper_h323_types.c
index 022c47b..4b35961 100644
--- a/net/ipv4/netfilter/ip_conntrack_helper_h323_types.c
+++ b/net/ipv4/netfilter/ip_conntrack_helper_h323_types.c
@@ -1,4 +1,4 @@
-/* Generated by Jing Min Zhao's ASN.1 parser, Mar 15 2006
+/* Generated by Jing Min Zhao's ASN.1 parser, Apr 20 2006
*
* Copyright (c) 2006 Jing Min Zhao <zhaojingmin@users.sourceforge.net>
*
@@ -1069,8 +1069,8 @@ static field_t _Facility_UUIE_fastStart[
static field_t _Facility_UUIE[] = { /* SEQUENCE */
{FNAME("protocolIdentifier") OID, BYTE, 0, 0, SKIP, 0, NULL},
- {FNAME("alternativeAddress") CHOICE, 3, 7, 7, SKIP | EXT | OPT, 0,
- _TransportAddress},
+ {FNAME("alternativeAddress") CHOICE, 3, 7, 7, DECODE | EXT | OPT,
+ offsetof(Facility_UUIE, alternativeAddress), _TransportAddress},
{FNAME("alternativeAliasAddress") SEQOF, SEMI, 0, 0, SKIP | OPT, 0,
_Facility_UUIE_alternativeAliasAddress},
{FNAME("conferenceID") OCTSTR, FIXD, 16, 0, SKIP | OPT, 0, NULL},
diff --git a/net/ipv4/netfilter/ip_nat_helper_h323.c b/net/ipv4/netfilter/ip_nat_helper_h323.c
index d45663d..419b878 100644
--- a/net/ipv4/netfilter/ip_nat_helper_h323.c
+++ b/net/ipv4/netfilter/ip_nat_helper_h323.c
@@ -487,6 +487,80 @@ static int nat_q931(struct sk_buff **psk
}
/****************************************************************************/
+static void ip_nat_callforwarding_expect(struct ip_conntrack *new,
+ struct ip_conntrack_expect *this)
+{
+ struct ip_nat_range range;
+
+ /* This must be a fresh one. */
+ BUG_ON(new->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 = new->tuplehash[!this->dir].tuple.src.ip;
+
+ /* hook doesn't matter, but it has to do source manip */
+ ip_nat_setup_info(new, &range, NF_IP_POST_ROUTING);
+
+ /* 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 = this->saved_proto;
+ range.min_ip = range.max_ip = this->saved_ip;
+
+ /* hook doesn't matter, but it has to do destination manip */
+ ip_nat_setup_info(new, &range, NF_IP_PRE_ROUTING);
+
+ ip_conntrack_q931_expect(new, this);
+}
+
+/****************************************************************************/
+static int nat_callforwarding(struct sk_buff **pskb, struct ip_conntrack *ct,
+ enum ip_conntrack_info ctinfo,
+ unsigned char **data, int dataoff,
+ TransportAddress * addr, u_int16_t port,
+ struct ip_conntrack_expect *exp)
+{
+ int dir = CTINFO2DIR(ctinfo);
+ u_int16_t nated_port;
+
+ /* Set expectations for NAT */
+ exp->saved_ip = exp->tuple.dst.ip;
+ exp->tuple.dst.ip = ct->tuplehash[!dir].tuple.dst.ip;
+ exp->saved_proto.tcp.port = exp->tuple.dst.u.tcp.port;
+ exp->expectfn = ip_nat_callforwarding_expect;
+ exp->dir = !dir;
+
+ /* Try to get same port: if not, try to change it. */
+ for (nated_port = port; nated_port != 0; nated_port++) {
+ exp->tuple.dst.u.tcp.port = htons(nated_port);
+ if (ip_conntrack_expect_related(exp) == 0)
+ break;
+ }
+
+ if (nated_port == 0) { /* No port available */
+ if (net_ratelimit())
+ printk("ip_nat_q931: out of TCP ports\n");
+ return 0;
+ }
+
+ /* Modify signal */
+ if (!set_h225_addr(pskb, data, dataoff, addr,
+ ct->tuplehash[!dir].tuple.dst.ip,
+ nated_port) == 0) {
+ ip_conntrack_unexpect_related(exp);
+ return -1;
+ }
+
+ /* Success */
+ DEBUGP("ip_nat_q931: expect Call Forwarding "
+ "%u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n",
+ NIPQUAD(exp->tuple.src.ip), ntohs(exp->tuple.src.u.tcp.port),
+ NIPQUAD(exp->tuple.dst.ip), ntohs(exp->tuple.dst.u.tcp.port));
+
+ return 0;
+}
+
+/****************************************************************************/
static int __init init(void)
{
BUG_ON(set_h245_addr_hook != NULL);
@@ -496,6 +570,7 @@ static int __init init(void)
BUG_ON(nat_rtp_rtcp_hook != NULL);
BUG_ON(nat_t120_hook != NULL);
BUG_ON(nat_h245_hook != NULL);
+ BUG_ON(nat_callforwarding_hook != NULL);
BUG_ON(nat_q931_hook != NULL);
set_h245_addr_hook = set_h245_addr;
@@ -505,6 +580,7 @@ static int __init init(void)
nat_rtp_rtcp_hook = nat_rtp_rtcp;
nat_t120_hook = nat_t120;
nat_h245_hook = nat_h245;
+ nat_callforwarding_hook = nat_callforwarding;
nat_q931_hook = nat_q931;
DEBUGP("ip_nat_h323: init success\n");
@@ -521,6 +597,7 @@ static void __exit fini(void)
nat_rtp_rtcp_hook = NULL;
nat_t120_hook = NULL;
nat_h245_hook = NULL;
+ nat_callforwarding_hook = NULL;
nat_q931_hook = NULL;
synchronize_net();
}
^ permalink raw reply related [flat|nested] 23+ messages in thread* [NETFILTER 15/17]: H.323 helper: replace internal_net_addr parameter by routing-based heuristic
2006-05-29 22:34 [NETFILTER 00/17]: Netfilter update for 2.6.18 Patrick McHardy
` (13 preceding siblings ...)
2006-05-29 22:34 ` [NETFILTER 14/17]: H.323 helper: Add support for Call Forwarding Patrick McHardy
@ 2006-05-29 22:34 ` Patrick McHardy
2006-05-29 22:34 ` [NETFILTER 16/17]: Add SIP connection tracking helper Patrick McHardy
` (2 subsequent siblings)
17 siblings, 0 replies; 23+ messages in thread
From: Patrick McHardy @ 2006-05-29 22:34 UTC (permalink / raw)
To: davem; +Cc: netfilter-devel, Patrick McHardy
[NETFILTER]: H.323 helper: replace internal_net_addr parameter by routing-based heuristic
Call Forwarding doesn't need to create an expectation if both peers can
reach each other without our help. The internal_net_addr parameter
lets the user explicitly specify a single network where this is true,
but is not very flexible and even fails in the common case that calls
will both be forwarded to outside parties and inside parties. Use an
optional heuristic based on routing instead, the assumption is that
if bpth the outgoing device and the gateway are equal, both peers can
reach each other directly.
Signed-off-by: Patrick McHardy <kaber@trash.net>
---
commit 4f26e484683957dde7142a135a8938efe9b69f5f
tree 02b20ac59b8a16cede8e2d4d590bc759ffc0c2de
parent cf55d393a491b6d441f36a68117e9bdfc8940a47
author Patrick McHardy <kaber@trash.net> Tue, 30 May 2006 00:08:45 +0200
committer Patrick McHardy <kaber@trash.net> Tue, 30 May 2006 00:08:45 +0200
net/ipv4/netfilter/ip_conntrack_helper_h323.c | 57 ++++++++++++-------------
1 files changed, 27 insertions(+), 30 deletions(-)
diff --git a/net/ipv4/netfilter/ip_conntrack_helper_h323.c b/net/ipv4/netfilter/ip_conntrack_helper_h323.c
index 3052468..0665674 100644
--- a/net/ipv4/netfilter/ip_conntrack_helper_h323.c
+++ b/net/ipv4/netfilter/ip_conntrack_helper_h323.c
@@ -40,12 +40,11 @@ static int gkrouted_only = 1;
module_param(gkrouted_only, int, 0600);
MODULE_PARM_DESC(gkrouted_only, "only accept calls from gatekeeper");
-static char *internal_net = NULL;
-static u_int32_t internal_net_addr = 0;
-static u_int32_t internal_net_mask = 0;
-module_param(internal_net, charp, 0600);
-MODULE_PARM_DESC(internal_net, "specify your internal network using format "
- "address/mask. this is used by call forwarding support");
+static int callforward_filter = 1;
+module_param(callforward_filter, bool, 0600);
+MODULE_PARM_DESC(callforward_filter, "only create call forwarding expectations "
+ "if both endpoints are on different sides "
+ "(determined by routing information)");
/* Hooks for NAT */
int (*set_h245_addr_hook) (struct sk_buff ** pskb,
@@ -721,12 +720,28 @@ static int expect_callforwarding(struct
/* If the calling party is on the same side of the forward-to party,
* we don't need to track the second call */
- if (internal_net &&
- ((ip & internal_net_mask) == internal_net_addr) ==
- ((ct->tuplehash[!dir].tuple.src.ip & internal_net_mask) ==
- internal_net_addr)) {
- DEBUGP("ip_ct_q931: Call Forwarding not tracked\n");
- return 0;
+ if (callforward_filter) {
+ struct rtable *rt1, *rt2;
+ struct flowi fl1 = {
+ .fl4_dst = ip,
+ };
+ struct flowi fl2 = {
+ .fl4_dst = ct->tuplehash[!dir].tuple.src.ip,
+ };
+
+ if (ip_route_output_key(&rt1, &fl1) == 0) {
+ if (ip_route_output_key(&rt2, &fl2) == 0) {
+ if (rt1->rt_gateway == rt2->rt_gateway &&
+ rt1->u.dst.dev == rt2->u.dst.dev)
+ ret = 1;
+ dst_release(&rt2->u.dst);
+ }
+ dst_release(&rt1->u.dst);
+ }
+ if (ret) {
+ DEBUGP("ip_ct_q931: Call Forwarding not tracked\n");
+ return 0;
+ }
}
/* Create expect for the second call leg */
@@ -1762,7 +1777,6 @@ static void fini(void)
static int __init init(void)
{
int ret;
- char *p;
h323_buffer = kmalloc(65536, GFP_KERNEL);
if (!h323_buffer)
@@ -1772,23 +1786,6 @@ static int __init init(void)
fini();
return ret;
}
-
- if (internal_net) {
- if ((p = strchr(internal_net, '/')))
- *p++ = 0;
- if (isdigit(internal_net[0])) {
- internal_net_addr = in_aton(internal_net);
- if (p && isdigit(p[0]))
- internal_net_mask = in_aton(p);
- else
- internal_net_mask = 0xffffffff;
- internal_net_addr &= internal_net_mask;
- }
- DEBUGP("ip_ct_h323: internal_net = %u.%u.%u.%u/%u.%u.%u.%u\n",
- NIPQUAD(internal_net_addr),
- NIPQUAD(internal_net_mask));
- }
-
DEBUGP("ip_ct_h323: init success\n");
return 0;
}
^ permalink raw reply related [flat|nested] 23+ messages in thread* [NETFILTER 16/17]: Add SIP connection tracking helper
2006-05-29 22:34 [NETFILTER 00/17]: Netfilter update for 2.6.18 Patrick McHardy
` (14 preceding siblings ...)
2006-05-29 22:34 ` [NETFILTER 15/17]: H.323 helper: replace internal_net_addr parameter by routing-based heuristic Patrick McHardy
@ 2006-05-29 22:34 ` Patrick McHardy
2006-05-29 22:34 ` [NETFILTER 17/17]: PPTP helper: fixup gre_keymap_lookup() return type Patrick McHardy
2006-05-30 1:27 ` [NETFILTER 00/17]: Netfilter update for 2.6.18 David Miller
17 siblings, 0 replies; 23+ messages in thread
From: Patrick McHardy @ 2006-05-29 22:34 UTC (permalink / raw)
To: davem; +Cc: netfilter-devel, Patrick McHardy
[NETFILTER]: Add SIP connection tracking helper
Add SIP connection tracking helper. Originally written by
Christian Hentschel <chentschel@arnet.com.ar>, some cleanup, minor
fixes and bidirectional SIP support added by myself.
Signed-off-by: Patrick McHardy <kaber@trash.net>
---
commit b82b2937b979e17f29c68496a99a68cee14ceab3
tree ab2f4f290134e1690450fb5b5c1797d110bfae30
parent 4f26e484683957dde7142a135a8938efe9b69f5f
author Patrick McHardy <kaber@trash.net> Tue, 30 May 2006 00:08:46 +0200
committer Patrick McHardy <kaber@trash.net> Tue, 30 May 2006 00:08:46 +0200
include/linux/netfilter_ipv4/ip_conntrack_sip.h | 44 ++
net/ipv4/netfilter/Kconfig | 18 +
net/ipv4/netfilter/Makefile | 2
net/ipv4/netfilter/ip_conntrack_sip.c | 471 +++++++++++++++++++++++
net/ipv4/netfilter/ip_nat_sip.c | 249 ++++++++++++
5 files changed, 784 insertions(+), 0 deletions(-)
diff --git a/include/linux/netfilter_ipv4/ip_conntrack_sip.h b/include/linux/netfilter_ipv4/ip_conntrack_sip.h
new file mode 100644
index 0000000..913dad6
--- /dev/null
+++ b/include/linux/netfilter_ipv4/ip_conntrack_sip.h
@@ -0,0 +1,44 @@
+#ifndef __IP_CONNTRACK_SIP_H__
+#define __IP_CONNTRACK_SIP_H__
+#ifdef __KERNEL__
+
+#define SIP_PORT 5060
+#define SIP_TIMEOUT 3600
+
+#define POS_VIA 0
+#define POS_CONTACT 1
+#define POS_CONTENT 2
+#define POS_MEDIA 3
+#define POS_OWNER 4
+#define POS_CONNECTION 5
+#define POS_REQ_HEADER 6
+#define POS_SDP_HEADER 7
+
+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 (*match_len)(const char *, const char *, int *);
+};
+
+extern unsigned int (*ip_nat_sip_hook)(struct sk_buff **pskb,
+ enum ip_conntrack_info ctinfo,
+ struct ip_conntrack *ct,
+ const char **dptr);
+extern unsigned int (*ip_nat_sdp_hook)(struct sk_buff **pskb,
+ enum ip_conntrack_info ctinfo,
+ struct ip_conntrack_expect *exp,
+ const char *dptr);
+
+extern int ct_sip_get_info(const char *dptr, size_t dlen,
+ unsigned int *matchoff,
+ unsigned int *matchlen,
+ struct sip_header_nfo *hnfo);
+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);
+#endif /* __KERNEL__ */
+#endif /* __IP_CONNTRACK_SIP_H__ */
diff --git a/net/ipv4/netfilter/Kconfig b/net/ipv4/netfilter/Kconfig
index fd37223..0e6c280 100644
--- a/net/ipv4/netfilter/Kconfig
+++ b/net/ipv4/netfilter/Kconfig
@@ -191,6 +191,18 @@ config IP_NF_H323
If you want to compile it as a module, say 'M' here and read
Documentation/modules.txt. If unsure, say 'N'.
+config IP_NF_SIP
+ tristate "SIP protocol support (EXPERIMENTAL)"
+ depends on IP_NF_CONNTRACK && EXPERIMENTAL
+ help
+ SIP is an application-layer control protocol that can establish,
+ modify, and terminate multimedia sessions (conferences) such as
+ Internet telephony calls. With the ip_conntrack_sip and
+ the ip_nat_sip modules you can support the protocol on a connection
+ tracking/NATing firewall.
+
+ To compile it as a module, choose M here. If unsure, say Y.
+
config IP_NF_QUEUE
tristate "IP Userspace queueing via NETLINK (OBSOLETE)"
help
@@ -503,6 +515,12 @@ config IP_NF_NAT_H323
default IP_NF_NAT if IP_NF_H323=y
default m if IP_NF_H323=m
+config IP_NF_NAT_SIP
+ tristate
+ depends on IP_NF_IPTABLES!=n && IP_NF_CONNTRACK!=n && IP_NF_NAT!=n
+ default IP_NF_NAT if IP_NF_SIP=y
+ default m if IP_NF_SIP=m
+
# mangle + specific targets
config IP_NF_MANGLE
tristate "Packet mangling"
diff --git a/net/ipv4/netfilter/Makefile b/net/ipv4/netfilter/Makefile
index 461cb1e..3ded4a3 100644
--- a/net/ipv4/netfilter/Makefile
+++ b/net/ipv4/netfilter/Makefile
@@ -31,6 +31,7 @@ obj-$(CONFIG_IP_NF_AMANDA) += ip_conntra
obj-$(CONFIG_IP_NF_TFTP) += ip_conntrack_tftp.o
obj-$(CONFIG_IP_NF_FTP) += ip_conntrack_ftp.o
obj-$(CONFIG_IP_NF_IRC) += ip_conntrack_irc.o
+obj-$(CONFIG_IP_NF_SIP) += ip_conntrack_sip.o
obj-$(CONFIG_IP_NF_NETBIOS_NS) += ip_conntrack_netbios_ns.o
# NAT helpers
@@ -40,6 +41,7 @@ obj-$(CONFIG_IP_NF_NAT_AMANDA) += ip_nat
obj-$(CONFIG_IP_NF_NAT_TFTP) += ip_nat_tftp.o
obj-$(CONFIG_IP_NF_NAT_FTP) += ip_nat_ftp.o
obj-$(CONFIG_IP_NF_NAT_IRC) += ip_nat_irc.o
+obj-$(CONFIG_IP_NF_NAT_SIP) += ip_nat_sip.o
# generic IP tables
obj-$(CONFIG_IP_NF_IPTABLES) += ip_tables.o
diff --git a/net/ipv4/netfilter/ip_conntrack_sip.c b/net/ipv4/netfilter/ip_conntrack_sip.c
new file mode 100644
index 0000000..fc87ce0
--- /dev/null
+++ b/net/ipv4/netfilter/ip_conntrack_sip.c
@@ -0,0 +1,471 @@
+/* SIP extension for IP connection tracking.
+ *
+ * (C) 2005 by Christian Hentschel <chentschel@arnet.com.ar>
+ * based on RR's ip_conntrack_ftp.c and other modules.
+ *
+ * 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
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/ctype.h>
+#include <linux/skbuff.h>
+#include <linux/in.h>
+#include <linux/ip.h>
+#include <linux/udp.h>
+
+#include <linux/netfilter.h>
+#include <linux/netfilter_ipv4.h>
+#include <linux/netfilter_ipv4/ip_conntrack_helper.h>
+#include <linux/netfilter_ipv4/ip_conntrack_sip.h>
+
+#if 0
+#define DEBUGP printk
+#else
+#define DEBUGP(format, args...)
+#endif
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Christian Hentschel <chentschel@arnet.com.ar>");
+MODULE_DESCRIPTION("SIP connection tracking helper");
+
+#define MAX_PORTS 8
+static unsigned short ports[MAX_PORTS];
+static int ports_c;
+module_param_array(ports, ushort, &ports_c, 0400);
+MODULE_PARM_DESC(ports, "port numbers of sip servers");
+
+static unsigned int sip_timeout = SIP_TIMEOUT;
+module_param(sip_timeout, uint, 0600);
+MODULE_PARM_DESC(sip_timeout, "timeout for the master SIP session");
+
+unsigned int (*ip_nat_sip_hook)(struct sk_buff **pskb,
+ enum ip_conntrack_info ctinfo,
+ struct ip_conntrack *ct,
+ const char **dptr);
+EXPORT_SYMBOL_GPL(ip_nat_sip_hook);
+
+unsigned int (*ip_nat_sdp_hook)(struct sk_buff **pskb,
+ enum ip_conntrack_info ctinfo,
+ struct ip_conntrack_expect *exp,
+ const char *dptr);
+EXPORT_SYMBOL_GPL(ip_nat_sdp_hook);
+
+int ct_sip_get_info(const char *dptr, size_t dlen,
+ unsigned int *matchoff,
+ unsigned int *matchlen,
+ struct sip_header_nfo *hnfo);
+EXPORT_SYMBOL_GPL(ct_sip_get_info);
+
+
+static int digits_len(const char *dptr, const char *limit, int *shift);
+static int epaddr_len(const char *dptr, const char *limit, int *shift);
+static int skp_digits_len(const char *dptr, const char *limit, int *shift);
+static int skp_epaddr_len(const char *dptr, const char *limit, int *shift);
+
+struct sip_header_nfo ct_sip_hdrs[] = {
+ { /* 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,
+ },
+ { /* 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
+ },
+ { /* 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
+ },
+ { /* SDP media info */
+ .lname = "\nm=",
+ .lnlen = sizeof("\nm=") - 1,
+ .sname = "\rm=",
+ .snlen = sizeof("\rm=") - 1,
+ .ln_str = "audio ",
+ .ln_strlen = sizeof("audio ") - 1,
+ .match_len = digits_len
+ },
+ { /* SDP owner address*/
+ .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
+ },
+ { /* SDP connection info */
+ .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
+ },
+ { /* Requests headers */
+ .lname = "sip:",
+ .lnlen = sizeof("sip:") - 1,
+ .sname = "sip:",
+ .snlen = sizeof("sip:") - 1, /* yes, i know.. ;) */
+ .ln_str = "@",
+ .ln_strlen = sizeof("@") - 1,
+ .match_len = epaddr_len
+ },
+ { /* SDP version header */
+ .lname = "\nv=",
+ .lnlen = sizeof("\nv=") - 1,
+ .sname = "\rv=",
+ .snlen = sizeof("\rv=") - 1,
+ .ln_str = "=",
+ .ln_strlen = sizeof("=") - 1,
+ .match_len = digits_len
+ }
+};
+EXPORT_SYMBOL_GPL(ct_sip_hdrs);
+
+/* get line lenght 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)
+{
+ const char *limit = haystack + (haystack_len - needle_len);
+
+ while (haystack <= limit) {
+ if (memcmp(haystack, needle, needle_len) == 0)
+ return haystack;
+ haystack++;
+ }
+ return NULL;
+}
+EXPORT_SYMBOL_GPL(ct_sip_search);
+
+static int digits_len(const char *dptr, const char *limit, int *shift)
+{
+ int len = 0;
+ while (dptr <= limit && isdigit(*dptr)) {
+ dptr++;
+ len++;
+ }
+ return len;
+}
+
+/* get digits lenght, skiping blank spaces. */
+static int skp_digits_len(const char *dptr, const char *limit, int *shift)
+{
+ for (; dptr <= limit && *dptr == ' '; dptr++)
+ (*shift)++;
+
+ return digits_len(dptr, limit, shift);
+}
+
+/* Simple ipaddr parser.. */
+static int parse_ipaddr(const char *cp, const char **endp,
+ u_int32_t *ipaddr, const char *limit)
+{
+ unsigned long int val;
+ int i, digit = 0;
+
+ for (i = 0, *ipaddr = 0; cp <= limit && i < 4; i++) {
+ digit = 0;
+ if (!isdigit(*cp))
+ break;
+
+ val = simple_strtoul(cp, (char **)&cp, 10);
+ if (val > 0xFF)
+ return -1;
+
+ ((u_int8_t *)ipaddr)[i] = val;
+ digit = 1;
+
+ if (*cp != '.')
+ break;
+ cp++;
+ }
+ if (!digit)
+ return -1;
+
+ if (endp)
+ *endp = cp;
+
+ return 0;
+}
+
+/* skip ip address. returns it lenght. */
+static int epaddr_len(const char *dptr, const char *limit, int *shift)
+{
+ const char *aux = dptr;
+ u_int32_t ip;
+
+ if (parse_ipaddr(dptr, &dptr, &ip, limit) < 0) {
+ DEBUGP("ip: %s parse failed.!\n", dptr);
+ return 0;
+ }
+
+ /* Port number */
+ if (*dptr == ':') {
+ dptr++;
+ dptr += digits_len(dptr, limit, shift);
+ }
+ return dptr - aux;
+}
+
+/* get address length, skiping user info. */
+static int skp_epaddr_len(const char *dptr, const char *limit, int *shift)
+{
+ int s = *shift;
+
+ for (; dptr <= limit && *dptr != '@'; dptr++)
+ (*shift)++;
+
+ if (*dptr == '@') {
+ dptr++;
+ (*shift)++;
+ } else
+ *shift = s;
+
+ return epaddr_len(dptr, limit, shift);
+}
+
+/* Returns 0 if not found, -1 error parsing. */
+int ct_sip_get_info(const char *dptr, size_t dlen,
+ unsigned int *matchoff,
+ unsigned int *matchlen,
+ struct sip_header_nfo *hnfo)
+{
+ const char *limit, *aux, *k = dptr;
+ int shift = 0;
+
+ limit = dptr + (dlen - hnfo->lnlen);
+
+ while (dptr <= limit) {
+ if ((strncmp(dptr, hnfo->lname, hnfo->lnlen) != 0) &&
+ (strncmp(dptr, hnfo->sname, hnfo->snlen) != 0)) {
+ dptr++;
+ continue;
+ }
+ aux = ct_sip_search(hnfo->ln_str, dptr, hnfo->ln_strlen,
+ ct_sip_lnlen(dptr, limit));
+ if (!aux) {
+ DEBUGP("'%s' not found in '%s'.\n", hnfo->ln_str,
+ hnfo->lname);
+ return -1;
+ }
+ aux += hnfo->ln_strlen;
+
+ *matchlen = hnfo->match_len(aux, limit, &shift);
+ if (!*matchlen)
+ return -1;
+
+ *matchoff = (aux - k) + shift;
+
+ DEBUGP("%s match succeeded! - len: %u\n", hnfo->lname,
+ *matchlen);
+ return 1;
+ }
+ DEBUGP("%s header not found.\n", hnfo->lname);
+ return 0;
+}
+
+static int set_expected_rtp(struct sk_buff **pskb,
+ struct ip_conntrack *ct,
+ enum ip_conntrack_info ctinfo,
+ u_int32_t ipaddr, u_int16_t port,
+ const char *dptr)
+{
+ struct ip_conntrack_expect *exp;
+ enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
+ int ret;
+
+ exp = ip_conntrack_expect_alloc(ct);
+ if (exp == NULL)
+ return NF_DROP;
+
+ exp->tuple.src.ip = ct->tuplehash[!dir].tuple.src.ip;
+ exp->tuple.src.u.udp.port = 0;
+ exp->tuple.dst.ip = ipaddr;
+ exp->tuple.dst.u.udp.port = htons(port);
+ exp->tuple.dst.protonum = IPPROTO_UDP;
+
+ exp->mask.src.ip = 0xFFFFFFFF;
+ exp->mask.src.u.udp.port = 0;
+ exp->mask.dst.ip = 0xFFFFFFFF;
+ exp->mask.dst.u.udp.port = 0xFFFF;
+ exp->mask.dst.protonum = 0xFF;
+
+ exp->expectfn = NULL;
+ exp->flags = 0;
+
+ if (ip_nat_sdp_hook)
+ ret = ip_nat_sdp_hook(pskb, ctinfo, exp, dptr);
+ else {
+ if (ip_conntrack_expect_related(exp) != 0)
+ ret = NF_DROP;
+ else
+ ret = NF_ACCEPT;
+ }
+ ip_conntrack_expect_put(exp);
+
+ return ret;
+}
+
+static int sip_help(struct sk_buff **pskb,
+ struct ip_conntrack *ct,
+ enum ip_conntrack_info ctinfo)
+{
+ unsigned int dataoff, datalen;
+ const char *dptr;
+ int ret = NF_ACCEPT;
+ int matchoff, matchlen;
+ u_int32_t ipaddr;
+ u_int16_t port;
+
+ /* No Data ? */
+ dataoff = (*pskb)->nh.iph->ihl*4 + sizeof(struct udphdr);
+ if (dataoff >= (*pskb)->len) {
+ DEBUGP("skb->len = %u\n", (*pskb)->len);
+ return NF_ACCEPT;
+ }
+
+ ip_ct_refresh(ct, *pskb, sip_timeout * HZ);
+
+ if (!skb_is_nonlinear(*pskb))
+ dptr = (*pskb)->data + dataoff;
+ else {
+ DEBUGP("Copy of skbuff not supported yet.\n");
+ goto out;
+ }
+
+ if (ip_nat_sip_hook) {
+ if (!ip_nat_sip_hook(pskb, ctinfo, ct, &dptr)) {
+ ret = NF_DROP;
+ goto out;
+ }
+ }
+
+ /* After this point NAT, could have mangled skb, so
+ we need to recalculate payload lenght. */
+ datalen = (*pskb)->len - dataoff;
+
+ if (datalen < (sizeof("SIP/2.0 200") - 1))
+ goto out;
+
+ /* RTP info only in some SDP pkts */
+ if (memcmp(dptr, "INVITE", sizeof("INVITE") - 1) != 0 &&
+ memcmp(dptr, "SIP/2.0 200", sizeof("SIP/2.0 200") - 1) != 0) {
+ goto out;
+ }
+ /* Get ip and port address from SDP packet. */
+ if (ct_sip_get_info(dptr, datalen, &matchoff, &matchlen,
+ &ct_sip_hdrs[POS_CONNECTION]) > 0) {
+
+ /* We'll drop only if there are parse problems. */
+ if (parse_ipaddr(dptr + matchoff, NULL, &ipaddr,
+ dptr + datalen) < 0) {
+ ret = NF_DROP;
+ goto out;
+ }
+ if (ct_sip_get_info(dptr, datalen, &matchoff, &matchlen,
+ &ct_sip_hdrs[POS_MEDIA]) > 0) {
+
+ port = simple_strtoul(dptr + matchoff, NULL, 10);
+ if (port < 1024) {
+ ret = NF_DROP;
+ goto out;
+ }
+ ret = set_expected_rtp(pskb, ct, ctinfo,
+ ipaddr, port, dptr);
+ }
+ }
+out:
+ return ret;
+}
+
+static struct ip_conntrack_helper sip[MAX_PORTS];
+static char sip_names[MAX_PORTS][10];
+
+static void fini(void)
+{
+ int i;
+ for (i = 0; i < ports_c; i++) {
+ DEBUGP("unregistering helper for port %d\n", ports[i]);
+ ip_conntrack_helper_unregister(&sip[i]);
+ }
+}
+
+static int __init init(void)
+{
+ int i, ret;
+ char *tmpname;
+
+ if (ports_c == 0)
+ ports[ports_c++] = SIP_PORT;
+
+ for (i = 0; i < ports_c; i++) {
+ /* Create helper structure */
+ memset(&sip[i], 0, sizeof(struct ip_conntrack_helper));
+
+ sip[i].tuple.dst.protonum = IPPROTO_UDP;
+ sip[i].tuple.src.u.udp.port = htons(ports[i]);
+ sip[i].mask.src.u.udp.port = 0xFFFF;
+ sip[i].mask.dst.protonum = 0xFF;
+ sip[i].max_expected = 1;
+ sip[i].timeout = 3 * 60; /* 3 minutes */
+ sip[i].me = THIS_MODULE;
+ sip[i].help = sip_help;
+
+ tmpname = &sip_names[i][0];
+ if (ports[i] == SIP_PORT)
+ sprintf(tmpname, "sip");
+ else
+ sprintf(tmpname, "sip-%d", i);
+ sip[i].name = tmpname;
+
+ DEBUGP("port #%d: %d\n", i, ports[i]);
+
+ ret = ip_conntrack_helper_register(&sip[i]);
+ if (ret) {
+ printk("ERROR registering helper for port %d\n",
+ ports[i]);
+ fini();
+ return ret;
+ }
+ }
+ return 0;
+}
+
+module_init(init);
+module_exit(fini);
diff --git a/net/ipv4/netfilter/ip_nat_sip.c b/net/ipv4/netfilter/ip_nat_sip.c
new file mode 100644
index 0000000..6ffba63
--- /dev/null
+++ b/net/ipv4/netfilter/ip_nat_sip.c
@@ -0,0 +1,249 @@
+/* SIP extension for UDP NAT alteration.
+ *
+ * (C) 2005 by Christian Hentschel <chentschel@arnet.com.ar>
+ * based on RR's ip_nat_ftp.c and other modules.
+ *
+ * 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
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/skbuff.h>
+#include <linux/ip.h>
+#include <linux/udp.h>
+
+#include <linux/netfilter_ipv4.h>
+#include <linux/netfilter_ipv4/ip_nat.h>
+#include <linux/netfilter_ipv4/ip_nat_helper.h>
+#include <linux/netfilter_ipv4/ip_conntrack_helper.h>
+#include <linux/netfilter_ipv4/ip_conntrack_sip.h>
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Christian Hentschel <chentschel@arnet.com.ar>");
+MODULE_DESCRIPTION("SIP NAT helper");
+
+#if 0
+#define DEBUGP printk
+#else
+#define DEBUGP(format, args...)
+#endif
+
+extern struct sip_header_nfo ct_sip_hdrs[];
+
+static unsigned int mangle_sip_packet(struct sk_buff **pskb,
+ enum ip_conntrack_info ctinfo,
+ struct ip_conntrack *ct,
+ const char **dptr, size_t dlen,
+ char *buffer, int bufflen,
+ struct sip_header_nfo *hnfo)
+{
+ unsigned int matchlen, matchoff;
+
+ if (ct_sip_get_info(*dptr, dlen, &matchoff, &matchlen, hnfo) <= 0)
+ return 0;
+
+ if (!ip_nat_mangle_udp_packet(pskb, ct, ctinfo,
+ matchoff, matchlen, buffer, bufflen))
+ return 0;
+
+ /* We need to reload this. Thanks Patrick. */
+ *dptr = (*pskb)->data + (*pskb)->nh.iph->ihl*4 + sizeof(struct udphdr);
+ return 1;
+}
+
+static unsigned int ip_nat_sip(struct sk_buff **pskb,
+ enum ip_conntrack_info ctinfo,
+ struct ip_conntrack *ct,
+ const char **dptr)
+{
+ enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
+ char buffer[sizeof("nnn.nnn.nnn.nnn:nnnnn")];
+ unsigned int bufflen, dataoff;
+ u_int32_t ip;
+ u_int16_t port;
+
+ dataoff = (*pskb)->nh.iph->ihl*4 + sizeof(struct udphdr);
+
+ ip = ct->tuplehash[!dir].tuple.dst.ip;
+ port = ct->tuplehash[!dir].tuple.dst.u.udp.port;
+ bufflen = sprintf(buffer, "%u.%u.%u.%u:%u", NIPQUAD(ip), ntohs(port));
+
+ /* short packet ? */
+ if (((*pskb)->len - dataoff) < (sizeof("SIP/2.0") - 1))
+ return 0;
+
+ /* Basic rules: requests and responses. */
+ if (memcmp(*dptr, "SIP/2.0", sizeof("SIP/2.0") - 1) == 0) {
+ const char *aux;
+
+ if ((ctinfo) < IP_CT_IS_REPLY) {
+ mangle_sip_packet(pskb, ctinfo, ct, dptr,
+ (*pskb)->len - dataoff,
+ buffer, bufflen,
+ &ct_sip_hdrs[POS_CONTACT]);
+ return 1;
+ }
+
+ if (!mangle_sip_packet(pskb, ctinfo, ct, dptr,
+ (*pskb)->len - dataoff,
+ buffer, bufflen, &ct_sip_hdrs[POS_VIA]))
+ return 0;
+
+ /* This search should ignore case, but later.. */
+ aux = ct_sip_search("CSeq:", *dptr, sizeof("CSeq:") - 1,
+ (*pskb)->len - dataoff);
+ if (!aux)
+ return 0;
+
+ if (!ct_sip_search("REGISTER", aux, sizeof("REGISTER"),
+ ct_sip_lnlen(aux, *dptr + (*pskb)->len - dataoff)))
+ return 1;
+
+ return mangle_sip_packet(pskb, ctinfo, ct, dptr,
+ (*pskb)->len - dataoff,
+ buffer, bufflen,
+ &ct_sip_hdrs[POS_CONTACT]);
+ }
+ if ((ctinfo) < IP_CT_IS_REPLY) {
+ if (!mangle_sip_packet(pskb, ctinfo, ct, dptr,
+ (*pskb)->len - dataoff,
+ buffer, bufflen, &ct_sip_hdrs[POS_VIA]))
+ return 0;
+
+ /* Mangle Contact if exists only. - watch udp_nat_mangle()! */
+ mangle_sip_packet(pskb, ctinfo, ct, dptr, (*pskb)->len - dataoff,
+ buffer, bufflen, &ct_sip_hdrs[POS_CONTACT]);
+ return 1;
+ }
+ /* This mangle requests headers. */
+ return mangle_sip_packet(pskb, ctinfo, ct, dptr,
+ ct_sip_lnlen(*dptr,
+ *dptr + (*pskb)->len - dataoff),
+ buffer, bufflen, &ct_sip_hdrs[POS_REQ_HEADER]);
+}
+
+static int mangle_content_len(struct sk_buff **pskb,
+ enum ip_conntrack_info ctinfo,
+ struct ip_conntrack *ct,
+ const char *dptr)
+{
+ unsigned int dataoff, matchoff, matchlen;
+ char buffer[sizeof("65536")];
+ int bufflen;
+
+ dataoff = (*pskb)->nh.iph->ihl*4 + sizeof(struct udphdr);
+
+ /* Get actual SDP lenght */
+ if (ct_sip_get_info(dptr, (*pskb)->len - dataoff, &matchoff,
+ &matchlen, &ct_sip_hdrs[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 = (*pskb)->len - dataoff - matchoff + 2;
+
+ /* Now, update SDP lenght */
+ if (ct_sip_get_info(dptr, (*pskb)->len - dataoff, &matchoff,
+ &matchlen, &ct_sip_hdrs[POS_CONTENT]) > 0) {
+
+ bufflen = sprintf(buffer, "%u", c_len);
+
+ return ip_nat_mangle_udp_packet(pskb, ct, ctinfo,
+ matchoff, matchlen,
+ buffer, bufflen);
+ }
+ }
+ return 0;
+}
+
+static unsigned int mangle_sdp(struct sk_buff **pskb,
+ enum ip_conntrack_info ctinfo,
+ struct ip_conntrack *ct,
+ u_int32_t newip, u_int16_t port,
+ const char *dptr)
+{
+ char buffer[sizeof("nnn.nnn.nnn.nnn")];
+ unsigned int dataoff, bufflen;
+
+ dataoff = (*pskb)->nh.iph->ihl*4 + sizeof(struct udphdr);
+
+ /* Mangle owner and contact info. */
+ bufflen = sprintf(buffer, "%u.%u.%u.%u", NIPQUAD(newip));
+ if (!mangle_sip_packet(pskb, ctinfo, ct, &dptr, (*pskb)->len - dataoff,
+ buffer, bufflen, &ct_sip_hdrs[POS_OWNER]))
+ return 0;
+
+ if (!mangle_sip_packet(pskb, ctinfo, ct, &dptr, (*pskb)->len - dataoff,
+ buffer, bufflen, &ct_sip_hdrs[POS_CONNECTION]))
+ return 0;
+
+ /* Mangle media port. */
+ bufflen = sprintf(buffer, "%u", port);
+ if (!mangle_sip_packet(pskb, ctinfo, ct, &dptr, (*pskb)->len - dataoff,
+ buffer, bufflen, &ct_sip_hdrs[POS_MEDIA]))
+ return 0;
+
+ return mangle_content_len(pskb, ctinfo, ct, dptr);
+}
+
+/* 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 **pskb,
+ enum ip_conntrack_info ctinfo,
+ struct ip_conntrack_expect *exp,
+ const char *dptr)
+{
+ struct ip_conntrack *ct = exp->master;
+ enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
+ u_int32_t newip;
+ u_int16_t port;
+
+ DEBUGP("ip_nat_sdp():\n");
+
+ /* Connection will come from reply */
+ newip = ct->tuplehash[!dir].tuple.dst.ip;
+
+ exp->tuple.dst.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_follow_master;
+
+ /* 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 (ip_conntrack_expect_related(exp) == 0)
+ break;
+ }
+
+ if (port == 0)
+ return NF_DROP;
+
+ if (!mangle_sdp(pskb, ctinfo, ct, newip, port, dptr)) {
+ ip_conntrack_unexpect_related(exp);
+ return NF_DROP;
+ }
+ return NF_ACCEPT;
+}
+
+static void __exit fini(void)
+{
+ ip_nat_sip_hook = NULL;
+ ip_nat_sdp_hook = NULL;
+ /* Make sure noone calls it, meanwhile. */
+ synchronize_net();
+}
+
+static int __init init(void)
+{
+ BUG_ON(ip_nat_sip_hook);
+ BUG_ON(ip_nat_sdp_hook);
+ ip_nat_sip_hook = ip_nat_sip;
+ ip_nat_sdp_hook = ip_nat_sdp;
+ return 0;
+}
+
+module_init(init);
+module_exit(fini);
^ permalink raw reply related [flat|nested] 23+ messages in thread* [NETFILTER 17/17]: PPTP helper: fixup gre_keymap_lookup() return type
2006-05-29 22:34 [NETFILTER 00/17]: Netfilter update for 2.6.18 Patrick McHardy
` (15 preceding siblings ...)
2006-05-29 22:34 ` [NETFILTER 16/17]: Add SIP connection tracking helper Patrick McHardy
@ 2006-05-29 22:34 ` Patrick McHardy
2006-05-30 1:27 ` [NETFILTER 00/17]: Netfilter update for 2.6.18 David Miller
17 siblings, 0 replies; 23+ messages in thread
From: Patrick McHardy @ 2006-05-29 22:34 UTC (permalink / raw)
To: davem; +Cc: netfilter-devel, Patrick McHardy
[NETFILTER]: PPTP helper: fixup gre_keymap_lookup() return type
GRE keys are 16-bit wide.
Signed-off-by: Alexey Dobriyan <adobriyan@gmail.com>
Signed-off-by: Patrick McHardy <kaber@trash.net>
---
commit 52bbecd4b81c32f9c8275aede42aed6897893349
tree 514f3c51a3d6df8905455169d05d8c633920dbff
parent b82b2937b979e17f29c68496a99a68cee14ceab3
author Alexey Dobriyan <adobriyan@gmail.com> Tue, 30 May 2006 00:08:47 +0200
committer Patrick McHardy <kaber@trash.net> Tue, 30 May 2006 00:08:47 +0200
net/ipv4/netfilter/ip_conntrack_proto_gre.c | 6 +++---
1 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/net/ipv4/netfilter/ip_conntrack_proto_gre.c b/net/ipv4/netfilter/ip_conntrack_proto_gre.c
index 5679479..21ee124 100644
--- a/net/ipv4/netfilter/ip_conntrack_proto_gre.c
+++ b/net/ipv4/netfilter/ip_conntrack_proto_gre.c
@@ -77,10 +77,10 @@ static inline int gre_key_cmpfn(const st
}
/* look up the source key for a given tuple */
-static u_int32_t gre_keymap_lookup(struct ip_conntrack_tuple *t)
+static __be16 gre_keymap_lookup(struct ip_conntrack_tuple *t)
{
struct ip_ct_gre_keymap *km;
- u_int32_t key = 0;
+ __be16 key = 0;
read_lock_bh(&ip_ct_gre_lock);
km = LIST_FIND(&gre_keymap_list, gre_key_cmpfn,
@@ -190,7 +190,7 @@ static int gre_pkt_to_tuple(const struct
struct ip_conntrack_tuple *tuple)
{
struct gre_hdr_pptp _pgrehdr, *pgrehdr;
- u_int32_t srckey;
+ __be16 srckey;
struct gre_hdr _grehdr, *grehdr;
/* first only delinearize old RFC1701 GRE header */
^ permalink raw reply related [flat|nested] 23+ messages in thread* Re: [NETFILTER 00/17]: Netfilter update for 2.6.18
2006-05-29 22:34 [NETFILTER 00/17]: Netfilter update for 2.6.18 Patrick McHardy
` (16 preceding siblings ...)
2006-05-29 22:34 ` [NETFILTER 17/17]: PPTP helper: fixup gre_keymap_lookup() return type Patrick McHardy
@ 2006-05-30 1:27 ` David Miller
17 siblings, 0 replies; 23+ messages in thread
From: David Miller @ 2006-05-30 1:27 UTC (permalink / raw)
To: kaber; +Cc: netfilter-devel
From: Patrick McHardy <kaber@trash.net>
Date: Tue, 30 May 2006 00:34:04 +0200 (MEST)
> following is a large netfilter update for 2.6.18 with changes all
> over the place, most noteworthy is the replacement of the recent
> match, a new SIP connection tracking helper and two new matches.
>
> Please apply to net-2.6.18, thanks.
All applied, thanks a lot Patrick.
^ permalink raw reply [flat|nested] 23+ messages in thread