2007-06-03 11:13:41

by Jan Engelhardt

[permalink] [raw]
Subject: [PATCH 0/2] xt_connlimit - connection limiting

Hello!


as with xt_u32, I would like to get xt_connlimit merged.
Find patches as a reply to this mail. Runtime tested.


Jan
--


2007-06-03 11:13:56

by Jan Engelhardt

[permalink] [raw]
Subject: [PATCH 1/2] xt_connlimit (kernel) - connection limiting


Adds the connlimit match that has been in POM-NG for a long time.

* works with 2.6.22, xtables'ified and all that

* will request nf_conntrack_ipv4 upon load
(otherwise it hotdrops every packet - a glitch that goes back
to at least 2.6.20.2)


Signed-off-by: Jan Engelhardt <[email protected]>

---
include/linux/netfilter/nf_conntrack_common.h | 1
include/linux/netfilter/xt_connlimit.h | 14 +
net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c | 5
net/netfilter/Kconfig | 7
net/netfilter/Makefile | 1
net/netfilter/xt_connlimit.c | 250 +++++++++++++++++++++++++
6 files changed, 278 insertions(+)

Index: linux-2.6.22-rc3-git6/include/linux/netfilter/nf_conntrack_common.h
===================================================================
--- linux-2.6.22-rc3-git6.orig/include/linux/netfilter/nf_conntrack_common.h
+++ linux-2.6.22-rc3-git6/include/linux/netfilter/nf_conntrack_common.h
@@ -164,6 +164,7 @@ struct ip_conntrack_stat

/* call to create an explicit dependency on nf_conntrack. */
extern void need_conntrack(void);
+extern void need_conntrack_ipv4(void);

#endif /* __KERNEL__ */

Index: linux-2.6.22-rc3-git6/include/linux/netfilter/xt_connlimit.h
===================================================================
--- /dev/null
+++ linux-2.6.22-rc3-git6/include/linux/netfilter/xt_connlimit.h
@@ -0,0 +1,14 @@
+#ifndef _XT_CONNLIMIT_H
+#define _XT_CONNLIMIT_H
+
+struct xt_connlimit_data;
+
+struct xt_connlimit_info {
+ uint32_t mask;
+ unsigned int limit, inverse;
+
+ /* this needs to be at the end */
+ struct xt_connlimit_data *data;
+};
+
+#endif /* _XT_CONNLIMIT_H */
Index: linux-2.6.22-rc3-git6/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c
===================================================================
--- linux-2.6.22-rc3-git6.orig/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c
+++ linux-2.6.22-rc3-git6/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c
@@ -519,3 +519,8 @@ static void __exit nf_conntrack_l3proto_

module_init(nf_conntrack_l3proto_ipv4_init);
module_exit(nf_conntrack_l3proto_ipv4_fini);
+
+void need_conntrack_ipv4(void)
+{
+}
+EXPORT_SYMBOL(need_conntrack_ipv4);
Index: linux-2.6.22-rc3-git6/net/netfilter/Kconfig
===================================================================
--- linux-2.6.22-rc3-git6.orig/net/netfilter/Kconfig
+++ linux-2.6.22-rc3-git6/net/netfilter/Kconfig
@@ -411,6 +411,13 @@ config NETFILTER_XT_MATCH_CONNBYTES
If you want to compile it as a module, say M here and read
<file:Documentation/kbuild/modules.txt>. If unsure, say `N'.

+config NETFILTER_XT_MATCH_CONNLIMIT
+ tristate '"connlimit" match support"'
+ depends on NETFILTER_XTABLES && NF_CONNTRACK_IPV4
+ ---help---
+ This match allows you to match against the number of parallel TCP
+ connections to a server per client IP address (or address block).
+
config NETFILTER_XT_MATCH_CONNMARK
tristate '"connmark" connection mark match support'
depends on NETFILTER_XTABLES
Index: linux-2.6.22-rc3-git6/net/netfilter/Makefile
===================================================================
--- linux-2.6.22-rc3-git6.orig/net/netfilter/Makefile
+++ linux-2.6.22-rc3-git6/net/netfilter/Makefile
@@ -51,6 +51,7 @@ obj-$(CONFIG_NETFILTER_XT_TARGET_CONNSEC
# matches
obj-$(CONFIG_NETFILTER_XT_MATCH_COMMENT) += xt_comment.o
obj-$(CONFIG_NETFILTER_XT_MATCH_CONNBYTES) += xt_connbytes.o
+obj-$(CONFIG_NETFILTER_XT_MATCH_CONNLIMIT) += xt_connlimit.o
obj-$(CONFIG_NETFILTER_XT_MATCH_CONNMARK) += xt_connmark.o
obj-$(CONFIG_NETFILTER_XT_MATCH_CONNTRACK) += xt_conntrack.o
obj-$(CONFIG_NETFILTER_XT_MATCH_DCCP) += xt_dccp.o
Index: linux-2.6.22-rc3-git6/net/netfilter/xt_connlimit.c
===================================================================
--- /dev/null
+++ linux-2.6.22-rc3-git6/net/netfilter/xt_connlimit.c
@@ -0,0 +1,250 @@
+/*
+ * netfilter module to limit the number of parallel tcp
+ * connections per IP address.
+ * (c) 2000 Gerd Knorr <[email protected]>
+ * Nov 2002: Martin Bene <[email protected]>:
+ * only ignore TIME_WAIT or gone connections
+ * © Jan Engelhardt <[email protected]>, 2007
+ *
+ * based on ...
+ *
+ * Kernel module to match connection tracking information.
+ * GPL (C) 1999 Rusty Russell ([email protected]).
+ */
+#include <linux/in.h>
+#include <linux/ip.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/skbuff.h>
+#include <linux/spinlock.h>
+#include <linux/netfilter/nf_conntrack_common.h>
+#include <linux/netfilter/nf_conntrack_tcp.h>
+#include <linux/netfilter/x_tables.h>
+#include <linux/netfilter/xt_connlimit.h>
+#include <net/netfilter/nf_conntrack.h>
+#include <net/netfilter/nf_conntrack_core.h>
+#include <net/netfilter/nf_conntrack_tuple.h>
+
+#define DEBUG 0
+
+/* we will save the tuples of all connections we care about */
+struct xt_connlimit_conn {
+ struct list_head list;
+ struct nf_conntrack_tuple tuple;
+};
+
+struct xt_connlimit_data {
+ struct list_head iphash[256];
+ spinlock_t lock;
+};
+
+static inline unsigned int connlimit_iphash(uint32_t addr)
+{
+ return (addr ^ (addr >> 8) ^ (addr >> 16) ^ (addr >> 24)) & 0xff;
+}
+
+static int count_them(struct xt_connlimit_data *data, uint32_t addr,
+ uint32_t mask, struct nf_conn *ct)
+{
+#if DEBUG
+ static const char const *tcp_state[] = {
+ "none", "established", "syn_sent", "syn_recv", "fin_wait",
+ "time_wait", "close", "close_wait", "last_ack", "listen"
+ };
+#endif
+ struct nf_conntrack_tuple_hash *found;
+ struct nf_conntrack_tuple tuple;
+ struct xt_connlimit_conn *conn;
+ struct list_head *hash, *lh;
+ int addit = 1, matches = 0;
+ struct nf_conn *found_ct;
+
+ spin_lock_bh(&data->lock);
+ tuple = ct->tuplehash[0].tuple;
+ hash = &data->iphash[connlimit_iphash(addr & mask)];
+
+ /* check the saved connections */
+ for (lh = hash->next; lh != hash; lh = lh->next) {
+ conn = list_entry(lh, struct xt_connlimit_conn, list);
+ found = nf_conntrack_find_get(&conn->tuple, ct);
+ found_ct = NULL;
+
+ if (found != NULL &&
+ (found_ct = nf_ct_tuplehash_to_ctrack(found)) != NULL &&
+ memcmp(&conn->tuple, &tuple, sizeof(tuple)) == 0 &&
+ found_ct->proto.tcp.state != TCP_CONNTRACK_TIME_WAIT)
+ /*
+ * Just to be sure we have it only once in the list.
+ * We should not see tuples twice unless someone hooks
+ * this into a table without "-p tcp --syn".
+ */
+ addit = 0;
+
+#if DEBUG
+ printk(KERN_WARNING "xt_connlimit [%u]: src=%u.%u.%u.%u:%u "
+ "dst=%u.%u.%u.%u:%d %s\n",
+ connlimit_iphash(addr & mask),
+ NIPQUAD(conn->tuple.src.u3.ip),
+ ntohs(conn->tuple.src.u.tcp.port),
+ NIPQUAD(conn->tuple.dst.u3.ip),
+ ntohs(conn->tuple.dst.u.tcp.port),
+ (found == NULL) ? "gone" :
+ tcp_state[found_ct->proto.tcp.state]);
+#endif
+
+ if (found == NULL) {
+ /* this one is gone */
+ lh = lh->prev;
+ list_del(lh->next);
+ kfree(conn);
+ continue;
+ }
+
+ if (found_ct->proto.tcp.state == TCP_CONNTRACK_TIME_WAIT) {
+ /*
+ * we do not care about connections which are
+ * closed already -> ditch it
+ */
+ lh = lh->prev;
+ list_del(lh->next);
+ kfree(conn);
+ nf_conntrack_put(&found_ct->ct_general);
+ continue;
+ }
+
+ if ((addr & mask) == (conn->tuple.src.u3.ip & mask))
+ /* same source IP address -> be counted! */
+ ++matches;
+
+ nf_conntrack_put(&found_ct->ct_general);
+ }
+
+ if (addit) {
+ /* save the new connection in our list */
+#if DEBUG
+ printk(KERN_WARNING "xt_connlimit [%u]: src=%u.%u.%u.%u:%u "
+ "dst=%u.%u.%u.%u:%u new\n",
+ connlimit_iphash(addr & mask),
+ NIPQUAD(tuple.src.u3.ip), ntohs(tuple.src.u.tcp.port),
+ NIPQUAD(tuple.dst.u3.ip), ntohs(tuple.dst.u.tcp.port));
+#endif
+
+ conn = kzalloc(sizeof(*conn), GFP_ATOMIC);
+ if (conn == NULL)
+ return -ENOMEM;
+
+ INIT_LIST_HEAD(&conn->list);
+ conn->tuple = tuple;
+ list_add(&conn->list, hash);
+ ++matches;
+ }
+
+ spin_unlock_bh(&data->lock);
+ return matches;
+}
+
+static int xt_connlimit_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)
+{
+ const struct xt_connlimit_info *info = matchinfo;
+ enum ip_conntrack_info ctinfo;
+ const struct iphdr *iph;
+ int connections, rv;
+ struct nf_conn *ct;
+
+ ct = nf_ct_get(skb, &ctinfo);
+ if (ct == NULL) {
+ printk(KERN_INFO "xt_connlimit: INVALID connection or "
+ "nf_conntrack_ipv4 not loaded\n");
+ *hotdrop = 1;
+ return false;
+ }
+
+ iph = ip_hdr(skb);
+ connections = count_them(info->data, iph->saddr, info->mask, ct);
+ if (connections < 0) {
+ /* kmalloc failed, drop it entirely */
+ printk(KERN_DEBUG "xt_connlimit: kmalloc failed\n");
+ *hotdrop = 1;
+ return false;
+ }
+
+ rv = info->inverse ^ (connections > info->limit);
+#if DEBUG
+ printk(KERN_DEBUG "xt_connlimit: src=%u.%u.%u.%u mask=%u.%u.%u.%u "
+ "connections=%d limit=%u match=%s\n",
+ NIPQUAD(iph->saddr), NIPQUAD(info->mask),
+ connections, info->limit, match ? "yes" : "no");
+#endif
+
+ return rv;
+}
+
+static int xt_connlimit_check(const char *tablename, const void *ip,
+ const struct xt_match *match, void *matchinfo,
+ unsigned int hook_mask)
+{
+ struct xt_connlimit_info *info = matchinfo;
+ unsigned int i;
+
+ /* init private data */
+ info->data = kmalloc(sizeof(struct xt_connlimit_data), GFP_KERNEL);
+ spin_lock_init(&info->data->lock);
+ for (i = 0; i < 256; ++i)
+ INIT_LIST_HEAD(&info->data->iphash[i]);
+
+ return 1;
+}
+
+static void xt_connlimit_destroy(const struct xt_match *match, void *matchinfo)
+{
+ struct xt_connlimit_info *info = matchinfo;
+ struct xt_connlimit_conn *conn;
+ struct list_head *hash;
+ unsigned int i;
+
+ for (i = 0; i < 256; ++i) {
+ hash = &info->data->iphash[i];
+ while (hash != hash->next) {
+ conn = list_entry(hash->next,
+ struct xt_connlimit_conn, list);
+ list_del(hash->next);
+ kfree(conn);
+ }
+ }
+
+ kfree(info->data);
+ return;
+}
+
+static struct xt_match xt_connlimit_reg = {
+ .name = "connlimit",
+ .family = AF_INET,
+ .proto = IPPROTO_TCP,
+ .checkentry = xt_connlimit_check,
+ .match = xt_connlimit_match,
+ .matchsize = sizeof(struct xt_connlimit_info),
+ .destroy = xt_connlimit_destroy,
+ .me = THIS_MODULE,
+};
+
+static int __init xt_connlimit_init(void)
+{
+ need_conntrack_ipv4();
+ return xt_register_match(&xt_connlimit_reg);
+}
+
+static void __exit xt_connlimit_exit(void)
+{
+ xt_unregister_match(&xt_connlimit_reg);
+ return;
+}
+
+module_init(xt_connlimit_init);
+module_exit(xt_connlimit_exit);
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("ipt_connlimit");

2007-06-03 11:15:03

by Jan Engelhardt

[permalink] [raw]
Subject: [PATCH 2/2] xt_connlimit (iptables) - connection limiting


Adds connlimit to iptables.

Signed-off-by: Jan Engelhardt <[email protected]>

---
extensions/.connlimit-test | 2
extensions/libipt_connlimit.c | 129 ++++++++++++++++++++++++++++++++++++++++
extensions/libipt_connlimit.man | 21 ++++++
3 files changed, 152 insertions(+)

Index: iptables/extensions/.connlimit-test
===================================================================
--- /dev/null
+++ iptables/extensions/.connlimit-test
@@ -0,0 +1,2 @@
+#!/bin/sh
+[ -f "$KERNEL_DIR/include/linux/netfilter/xt_connlimit.h" ] && echo connlimit
Index: iptables/extensions/libipt_connlimit.c
===================================================================
--- /dev/null
+++ iptables/extensions/libipt_connlimit.c
@@ -0,0 +1,129 @@
+/* Shared library add-on to iptables to add connection limit support. */
+#include <stdio.h>
+#include <netdb.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <getopt.h>
+#include <iptables.h>
+#include <linux/netfilter_ipv4/ip_conntrack.h>
+#include <linux/netfilter_ipv4/xt_connlimit.h>
+
+/* Function which prints out usage message. */
+static void help(void)
+{
+ printf(
+"connlimit v%s options:\n"
+"[!] --connlimit-above n match if the number of existing tcp connections is (not) above n\n"
+" --connlimit-mask n group hosts using mask\n"
+"\n", IPTABLES_VERSION);
+}
+
+static struct option opts[] = {
+ {"connlimit-above", 1, NULL, '1'},
+ {"connlimit-mask", 1, NULL, '2'},
+ {NULL},
+};
+
+/* Function which parses command options; returns true if it
+ ate an option */
+static int parse(int c, char **argv, int invert, unsigned int *flags,
+ const struct ipt_entry *entry, unsigned int *nfcache,
+ struct ipt_entry_match **match)
+{
+ struct xt_connlimit_info *info = (void *)(*match)->data;
+ int i;
+
+ if (!(*flags & 2))
+ /*
+ * set default mask unless we have already seen a mask option
+ */
+ info->mask = htonl(0xFFFFFFFF);
+
+ switch (c) {
+ case '1':
+ check_inverse(optarg, &invert, &optind, 0);
+ info->limit = strtoul(argv[optind-1], NULL, 0);
+ info->inverse = invert;
+ *flags |= 1;
+ break;
+
+ case '2':
+ i = strtol(argv[optind-1], NULL, 0);
+ if (i < 0 || i > 32)
+ exit_error(PARAMETER_PROBLEM,
+ "--connlimit-mask must be between 0 and 32");
+
+ if (i == 0)
+ info->mask = 0;
+ else
+ info->mask = htonl(0xFFFFFFFF << (32 - i));
+
+ *flags |= 2;
+ break;
+
+ default:
+ return 0;
+ }
+
+ return 1;
+}
+
+/* Final check */
+static void final_check(unsigned int flags)
+{
+ if (!(flags & 1))
+ exit_error(PARAMETER_PROBLEM, "You must specify `--connlimit-above'");
+}
+
+static int count_bits(u_int32_t mask)
+{
+ int i, bits;
+
+ for (bits = 0, i = 31; i >= 0; i--) {
+ if (mask & htonl((u_int32_t)1 << i)) {
+ bits++;
+ continue;
+ }
+ break;
+ }
+ return bits;
+}
+
+/* Prints out the matchinfo. */
+static void print(const struct ipt_ip *ip, const struct ipt_entry_match *match,
+ int numeric)
+{
+ const struct xt_connlimit_info *info = (const void *)match->data;
+
+ printf("#conn/%d %s %d ", count_bits(info->mask),
+ info->inverse ? "<" : ">", info->limit);
+}
+
+/* Saves the matchinfo in parsable form to stdout. */
+static void save(const struct ipt_ip *ip, const struct ipt_entry_match *match)
+{
+ const struct xt_connlimit_info *info = (const void *)match->data;
+
+ printf("%s--connlimit-above %u --connlimit-mask %u ",
+ info->inverse ? "! " : "", info->limit,
+ count_bits(info->mask));
+}
+
+static struct iptables_match connlimit = {
+ .name = "connlimit",
+ .version = IPTABLES_VERSION,
+ .size = IPT_ALIGN(sizeof(struct xt_connlimit_info)),
+ .userspacesize = offsetof(struct xt_connlimit_info, data),
+ .help = help,
+ .parse = parse,
+ .final_check = final_check,
+ .print = print,
+ .save = save,
+ .extra_opts = opts,
+};
+
+static __attribute__((constructor)) void libipt_connlimit_init(void)
+{
+ register_match(&connlimit);
+}
Index: iptables/extensions/libipt_connlimit.man
===================================================================
--- /dev/null
+++ iptables/extensions/libipt_connlimit.man
@@ -0,0 +1,21 @@
+Allows you to restrict the number of parallel TCP connections to a
+server per client IP address (or address block).
+.TP
+[\fB!\fR] \fB--connlimit-above \fIn\fR
+match if the number of existing tcp connections is (not) above n
+.TP
+.BI "--connlimit-mask " "bits"
+group hosts using mask
+.P
+Examples:
+.TP
+# allow 2 telnet connections per client host
+iptables -A INPUT -p tcp --syn --dport 23 -m connlimit --connlimit-above 2 -j REJECT
+.TP
+# you can also match the other way around:
+iptables -A INPUT -p tcp --syn --dport 23 -m connlimit ! --connlimit-above 2 -j ACCEPT
+.TP
+# limit the nr of parallel http requests to 16 per class C sized \
+network (24 bit netmask)
+iptables -p tcp --syn --dport 80 -m connlimit --connlimit-above 16
+--connlimit-mask 24 -j REJECT

2007-06-03 11:24:50

by Jan Engelhardt

[permalink] [raw]
Subject: Re: [PATCH 2/2] xt_connlimit (iptables) - connection limiting


Previous patch had a wrong #include line, this one seems better :)

================

Adds connlimit to iptables.

Signed-off-by: Jan Engelhardt <[email protected]>

---
extensions/.connlimit-test | 2
extensions/libipt_connlimit.c | 129 ++++++++++++++++++++++++++++++++++++++++
extensions/libipt_connlimit.man | 21 ++++++
3 files changed, 152 insertions(+)

Index: iptables/extensions/.connlimit-test
===================================================================
--- /dev/null
+++ iptables/extensions/.connlimit-test
@@ -0,0 +1,2 @@
+#!/bin/sh
+[ -f "$KERNEL_DIR/include/linux/netfilter/xt_connlimit.h" ] && echo connlimit
Index: iptables/extensions/libipt_connlimit.c
===================================================================
--- /dev/null
+++ iptables/extensions/libipt_connlimit.c
@@ -0,0 +1,129 @@
+/* Shared library add-on to iptables to add connection limit support. */
+#include <stdio.h>
+#include <netdb.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <getopt.h>
+#include <iptables.h>
+#include <linux/netfilter_ipv4/ip_conntrack.h>
+#include <linux/netfilter/xt_connlimit.h>
+
+/* Function which prints out usage message. */
+static void help(void)
+{
+ printf(
+"connlimit v%s options:\n"
+"[!] --connlimit-above n match if the number of existing tcp connections is (not) above n\n"
+" --connlimit-mask n group hosts using mask\n"
+"\n", IPTABLES_VERSION);
+}
+
+static struct option opts[] = {
+ {"connlimit-above", 1, NULL, '1'},
+ {"connlimit-mask", 1, NULL, '2'},
+ {NULL},
+};
+
+/* Function which parses command options; returns true if it
+ ate an option */
+static int parse(int c, char **argv, int invert, unsigned int *flags,
+ const struct ipt_entry *entry, unsigned int *nfcache,
+ struct ipt_entry_match **match)
+{
+ struct xt_connlimit_info *info = (void *)(*match)->data;
+ int i;
+
+ if (!(*flags & 2))
+ /*
+ * set default mask unless we have already seen a mask option
+ */
+ info->mask = htonl(0xFFFFFFFF);
+
+ switch (c) {
+ case '1':
+ check_inverse(optarg, &invert, &optind, 0);
+ info->limit = strtoul(argv[optind-1], NULL, 0);
+ info->inverse = invert;
+ *flags |= 1;
+ break;
+
+ case '2':
+ i = strtol(argv[optind-1], NULL, 0);
+ if (i < 0 || i > 32)
+ exit_error(PARAMETER_PROBLEM,
+ "--connlimit-mask must be between 0 and 32");
+
+ if (i == 0)
+ info->mask = 0;
+ else
+ info->mask = htonl(0xFFFFFFFF << (32 - i));
+
+ *flags |= 2;
+ break;
+
+ default:
+ return 0;
+ }
+
+ return 1;
+}
+
+/* Final check */
+static void final_check(unsigned int flags)
+{
+ if (!(flags & 1))
+ exit_error(PARAMETER_PROBLEM, "You must specify `--connlimit-above'");
+}
+
+static int count_bits(u_int32_t mask)
+{
+ int i, bits;
+
+ for (bits = 0, i = 31; i >= 0; i--) {
+ if (mask & htonl((u_int32_t)1 << i)) {
+ bits++;
+ continue;
+ }
+ break;
+ }
+ return bits;
+}
+
+/* Prints out the matchinfo. */
+static void print(const struct ipt_ip *ip, const struct ipt_entry_match *match,
+ int numeric)
+{
+ const struct xt_connlimit_info *info = (const void *)match->data;
+
+ printf("#conn/%d %s %d ", count_bits(info->mask),
+ info->inverse ? "<" : ">", info->limit);
+}
+
+/* Saves the matchinfo in parsable form to stdout. */
+static void save(const struct ipt_ip *ip, const struct ipt_entry_match *match)
+{
+ const struct xt_connlimit_info *info = (const void *)match->data;
+
+ printf("%s--connlimit-above %u --connlimit-mask %u ",
+ info->inverse ? "! " : "", info->limit,
+ count_bits(info->mask));
+}
+
+static struct iptables_match connlimit = {
+ .name = "connlimit",
+ .version = IPTABLES_VERSION,
+ .size = IPT_ALIGN(sizeof(struct xt_connlimit_info)),
+ .userspacesize = offsetof(struct xt_connlimit_info, data),
+ .help = help,
+ .parse = parse,
+ .final_check = final_check,
+ .print = print,
+ .save = save,
+ .extra_opts = opts,
+};
+
+static __attribute__((constructor)) void libipt_connlimit_init(void)
+{
+ register_match(&connlimit);
+}
Index: iptables/extensions/libipt_connlimit.man
===================================================================
--- /dev/null
+++ iptables/extensions/libipt_connlimit.man
@@ -0,0 +1,21 @@
+Allows you to restrict the number of parallel TCP connections to a
+server per client IP address (or address block).
+.TP
+[\fB!\fR] \fB--connlimit-above \fIn\fR
+match if the number of existing tcp connections is (not) above n
+.TP
+.BI "--connlimit-mask " "bits"
+group hosts using mask
+.P
+Examples:
+.TP
+# allow 2 telnet connections per client host
+iptables -A INPUT -p tcp --syn --dport 23 -m connlimit --connlimit-above 2 -j REJECT
+.TP
+# you can also match the other way around:
+iptables -A INPUT -p tcp --syn --dport 23 -m connlimit ! --connlimit-above 2 -j ACCEPT
+.TP
+# limit the nr of parallel http requests to 16 per class C sized \
+network (24 bit netmask)
+iptables -p tcp --syn --dport 80 -m connlimit --connlimit-above 16
+--connlimit-mask 24 -j REJECT

2007-06-03 11:51:18

by Yasuyuki KOZAKAI

[permalink] [raw]
Subject: Re: [PATCH 1/2] xt_connlimit (kernel) - connection limiting


Hi,

From: Jan Engelhardt <[email protected]>
Date: Sun, 3 Jun 2007 13:12:55 +0200 (MEST)

> +static int __init xt_connlimit_init(void)
> +{
> + need_conntrack_ipv4();
> + return xt_register_match(&xt_connlimit_reg);
> +}

You can use nf_ct_l3proto_try_module_get() instead of introducing
need_conntrack_ipv4(). Please refer xt_state.c and xt_conntrack.c as
example.

-- Yasuyuki Kozakai

2007-06-03 12:37:30

by Jan Engelhardt

[permalink] [raw]
Subject: Re: [PATCH 1/2] xt_connlimit (kernel) - connection limiting

Hello,

>From: Jan Engelhardt <[email protected]>
>Date: Sun, 3 Jun 2007 13:12:55 +0200 (MEST)
>
>> +static int __init xt_connlimit_init(void)
>> +{
>> + need_conntrack_ipv4();
>> + return xt_register_match(&xt_connlimit_reg);
>> +}
>
>You can use nf_ct_l3proto_try_module_get() instead of introducing
>need_conntrack_ipv4(). Please refer xt_state.c and xt_conntrack.c as
>example.

Thank you for this hint. I will add it and post updates versions
of the patch(es) when I am done with all.


Thanks,
Jan
--

2007-06-03 17:08:27

by Andrew Beverley

[permalink] [raw]
Subject: Re: [PATCH 1/2] xt_connlimit (kernel) - connection limiting

On Sun, 2007-06-03 at 13:12 +0200, Jan Engelhardt wrote:
> Adds the connlimit match that has been in POM-NG for a long time.
>
> * works with 2.6.22, xtables'ified and all that
>
> * will request nf_conntrack_ipv4 upon load
> (otherwise it hotdrops every packet - a glitch that goes back
> to at least 2.6.20.2)

Excellent! This has been at the back of my mind for a while.

Is there any chance of getting UDP flows added as well as TCP
connections? I use connlimit for detecting p2p software, but some p2p
software now uses UDP instead.

Thanks,

Andy Beverley


2007-06-03 17:20:35

by Jan Engelhardt

[permalink] [raw]
Subject: Re: [PATCH 1/2] xt_connlimit (kernel) - connection limiting


On Jun 3 2007 18:00, Andrew Beverley wrote:
>On Sun, 2007-06-03 at 13:12 +0200, Jan Engelhardt wrote:
>> Adds the connlimit match that has been in POM-NG for a long time.
>>
>> * works with 2.6.22, xtables'ified and all that
>>
>> * will request nf_conntrack_ipv4 upon load
>> (otherwise it hotdrops every packet - a glitch that goes back
>> to at least 2.6.20.2)
>
>Excellent! This has been at the back of my mind for a while.
>
>Is there any chance of getting UDP flows added as well as TCP
>connections?

I dare to say it's easy. The real problem is rather, that UDP is
connectionless, so for one, connlimit can, by definition of the word
'connectionless', not apply to UDP, though it is technically
possible. Second, because UDP "connections" "fly" (timeout after 30
seconds), just spewing one UDP packet out may kill another connection
(e.g. if you use connlimit in conjunction with DROP or REJECT).
What's more, UDP packets can be easily forged, much more than TCP, so
anyone on the same subtree (not subnet, because that's something
different) can send a bogus UDP packet and stop your connections from
working.
Let's see how to implement UDP counting...


Jan
--

2007-06-03 18:32:19

by Andrew Beverley

[permalink] [raw]
Subject: Re: [PATCH 1/2] xt_connlimit (kernel) - connection limiting

On Sun, 2007-06-03 at 19:18 +0200, Jan Engelhardt wrote:
> On Jun 3 2007 18:00, Andrew Beverley wrote:
> >On Sun, 2007-06-03 at 13:12 +0200, Jan Engelhardt wrote:
> >> Adds the connlimit match that has been in POM-NG for a long time.
> >>
> >> * works with 2.6.22, xtables'ified and all that
> >>
> >> * will request nf_conntrack_ipv4 upon load
> >> (otherwise it hotdrops every packet - a glitch that goes back
> >> to at least 2.6.20.2)
> >
> >Excellent! This has been at the back of my mind for a while.
> >
> >Is there any chance of getting UDP flows added as well as TCP
> >connections?
>
> I dare to say it's easy. The real problem is rather, that UDP is
> connectionless, so for one, connlimit can, by definition of the word
> 'connectionless', not apply to UDP, though it is technically
> possible.

Understood.

> Second, because UDP "connections" "fly" (timeout after 30
> seconds), just spewing one UDP packet out may kill another connection
> (e.g. if you use connlimit in conjunction with DROP or REJECT).

I see what you mean, although I personally would use this with an IPSET
target, and I would argue it is the responsibility of the administrator
to ensure it is used correctly.

> What's more, UDP packets can be easily forged, much more than TCP, so
> anyone on the same subtree (not subnet, because that's something
> different) can send a bogus UDP packet and stop your connections from
> working.

I didn't know that, but I doubt anyone where I would use it would be
able to do that :-)

> Let's see how to implement UDP counting...

The alternative, as I see it, is to adapt hashlimit to have an option to
limit by number of different concurrent streams to different port
numbers (but same source/destination IP address). However, I personally
think it would sit better in connlimit, even if UDP is not a connection
by strict definition.

Is it something you would consider, or shall I look at it myself?

With regards to Patrick's comment, IIRC this was one of the points he
originally raised.

Regards,

Andy Beverley