* [PATCH 2.6] Allow dynamic helper-port assignment
@ 2005-02-13 16:56 Harald Welte
2005-02-13 17:34 ` Max Kellermann
` (2 more replies)
0 siblings, 3 replies; 6+ messages in thread
From: Harald Welte @ 2005-02-13 16:56 UTC (permalink / raw)
To: Netfilter Development Mailinglist
[-- Attachment #1.1: Type: text/plain, Size: 1108 bytes --]
Hi!
The recent problem with h323 made me again consider the old idea of
having runtime-configurable port assignments for helpers.
Ideally, we would actually have conntrack helpers be iptables targets,
this way allowing totally dynamic assignemnt. Maybe yet another
pkttables todo.
Meanwhile, the following patch uses the same mechanism as CLUSTERIP:
Add port 2121 to ftp helper:
echo "+2121" > /proc/net/ip_conntrack_helper/ftp
Remove port 6669 from irc helper:
echo "-6669" > /proc/net/ip_conntrack_helper/irc
Show registered ports for amanda helper:
cat /proc/net/ip_conntrack_helper/amanda
If nobody complains, we should push this for 2.6.12.
And yes, I'll do the nf_conntrack merge right now :)
--
- Harald Welte <laforge@netfilter.org> http://www.netfilter.org/
============================================================================
"Fragmentation is like classful addressing -- an interesting early
architectural error that shows how much experimentation was going
on while IP was being designed." -- Paul Vixie
[-- Attachment #1.2: 2.6.11-rc4-ip_conntrack_helper_proc.patch --]
[-- Type: text/plain, Size: 21772 bytes --]
diff -Nru --exclude .depend --exclude '*.o' --exclude '*.ko' --exclude '*.ver' --exclude '.*.flags' --exclude '*.orig' --exclude '*.rej' --exclude '*.cmd' --exclude '*.mod.c' --exclude '*~' linux-2.6.11-rc4/include/linux/netfilter_ipv4/ip_conntrack_core.h linux-2.6.11-rc4-helper_sysctl/include/linux/netfilter_ipv4/ip_conntrack_core.h
--- linux-2.6.11-rc4/include/linux/netfilter_ipv4/ip_conntrack_core.h 2005-02-13 13:52:05.000000000 +0100
+++ linux-2.6.11-rc4-helper_sysctl/include/linux/netfilter_ipv4/ip_conntrack_core.h 2005-02-13 16:15:56.000000000 +0100
@@ -48,5 +48,10 @@
extern struct list_head *ip_conntrack_hash;
extern struct list_head ip_conntrack_expect_list;
DECLARE_RWLOCK_EXTERN(ip_conntrack_lock);
+extern struct list_head ip_conntrack_unconfirmed;
+
+extern void __ip_ct_destroy_expect(struct ip_conntrack_expect *exp);
+extern void __ip_ct_unlink_expect(struct ip_conntrack_expect *exp);
+
#endif /* _IP_CONNTRACK_CORE_H */
diff -Nru --exclude .depend --exclude '*.o' --exclude '*.ko' --exclude '*.ver' --exclude '.*.flags' --exclude '*.orig' --exclude '*.rej' --exclude '*.cmd' --exclude '*.mod.c' --exclude '*~' linux-2.6.11-rc4/include/linux/netfilter_ipv4/ip_conntrack_helper.h linux-2.6.11-rc4-helper_sysctl/include/linux/netfilter_ipv4/ip_conntrack_helper.h
--- linux-2.6.11-rc4/include/linux/netfilter_ipv4/ip_conntrack_helper.h 2005-02-13 13:52:05.000000000 +0100
+++ linux-2.6.11-rc4-helper_sysctl/include/linux/netfilter_ipv4/ip_conntrack_helper.h 2005-02-13 16:44:16.000000000 +0100
@@ -15,6 +15,10 @@
* expected connections */
unsigned int timeout; /* timeout for expecteds */
+#ifdef CONFIG_PROC_FS
+ struct proc_dir_entry *pde; /* proc file for port changes */
+#endif
+
/* Mask of things we will help (compared against server response) */
struct ip_conntrack_tuple tuple;
struct ip_conntrack_tuple mask;
@@ -29,6 +33,11 @@
extern int ip_conntrack_helper_register(struct ip_conntrack_helper *);
extern void ip_conntrack_helper_unregister(struct ip_conntrack_helper *);
+extern int ip_conntrack_helper_add_port(struct ip_conntrack_helper *h,
+ u_int16_t port);
+extern int ip_conntrack_helper_del_port(struct ip_conntrack_helper *h,
+ u_int16_t port);
+
/* Allocate space for an expectation: this is mandatory before calling
ip_conntrack_expect_related. */
extern struct ip_conntrack_expect *ip_conntrack_expect_alloc(void);
@@ -38,4 +47,10 @@
extern int ip_conntrack_expect_related(struct ip_conntrack_expect *exp);
extern void ip_conntrack_unexpect_related(struct ip_conntrack_expect *exp);
+/* Find the helper for a for a particular tuple */
+extern struct ip_conntrack_helper *ip_ct_find_helper(const struct ip_conntrack_tuple *tuple);
+
+extern int ip_conntrack_helper_init(void);
+extern void ip_conntrack_helper_fini(void);
+
#endif /*_IP_CONNTRACK_HELPER_H*/
diff -Nru --exclude .depend --exclude '*.o' --exclude '*.ko' --exclude '*.ver' --exclude '.*.flags' --exclude '*.orig' --exclude '*.rej' --exclude '*.cmd' --exclude '*.mod.c' --exclude '*~' linux-2.6.11-rc4/net/ipv4/netfilter/Makefile linux-2.6.11-rc4-helper_sysctl/net/ipv4/netfilter/Makefile
--- linux-2.6.11-rc4/net/ipv4/netfilter/Makefile 2005-02-13 13:52:06.000000000 +0100
+++ linux-2.6.11-rc4-helper_sysctl/net/ipv4/netfilter/Makefile 2005-02-13 13:59:13.000000000 +0100
@@ -3,7 +3,7 @@
#
# objects for the standalone - connection tracking / NAT
-ip_conntrack-objs := ip_conntrack_standalone.o ip_conntrack_core.o ip_conntrack_proto_generic.o ip_conntrack_proto_tcp.o ip_conntrack_proto_udp.o ip_conntrack_proto_icmp.o
+ip_conntrack-objs := ip_conntrack_standalone.o ip_conntrack_core.o ip_conntrack_helper.o ip_conntrack_proto_generic.o ip_conntrack_proto_tcp.o ip_conntrack_proto_udp.o ip_conntrack_proto_icmp.o
iptable_nat-objs := ip_nat_standalone.o ip_nat_rule.o ip_nat_core.o ip_nat_helper.o ip_nat_proto_unknown.o ip_nat_proto_tcp.o ip_nat_proto_udp.o ip_nat_proto_icmp.o
# connection tracking
diff -Nru --exclude .depend --exclude '*.o' --exclude '*.ko' --exclude '*.ver' --exclude '.*.flags' --exclude '*.orig' --exclude '*.rej' --exclude '*.cmd' --exclude '*.mod.c' --exclude '*~' linux-2.6.11-rc4/net/ipv4/netfilter/ip_conntrack_amanda.c linux-2.6.11-rc4-helper_sysctl/net/ipv4/netfilter/ip_conntrack_amanda.c
--- linux-2.6.11-rc4/net/ipv4/netfilter/ip_conntrack_amanda.c 2005-02-13 13:52:06.000000000 +0100
+++ linux-2.6.11-rc4-helper_sysctl/net/ipv4/netfilter/ip_conntrack_amanda.c 2005-02-13 17:41:38.000000000 +0100
@@ -160,7 +160,11 @@
static int __init init(void)
{
- return ip_conntrack_helper_register(&amanda_helper);
+ int ret = ip_conntrack_helper_register(&amanda_helper);
+ if (ret)
+ return ret;
+ return ip_conntrack_helper_add_port(&amanda_helper,
+ ntohs(amanda_helper.tuple.src.u.tcp.port));
}
module_init(init);
diff -Nru --exclude .depend --exclude '*.o' --exclude '*.ko' --exclude '*.ver' --exclude '.*.flags' --exclude '*.orig' --exclude '*.rej' --exclude '*.cmd' --exclude '*.mod.c' --exclude '*~' linux-2.6.11-rc4/net/ipv4/netfilter/ip_conntrack_core.c linux-2.6.11-rc4-helper_sysctl/net/ipv4/netfilter/ip_conntrack_core.c
--- linux-2.6.11-rc4/net/ipv4/netfilter/ip_conntrack_core.c 2005-02-13 13:52:06.000000000 +0100
+++ linux-2.6.11-rc4-helper_sysctl/net/ipv4/netfilter/ip_conntrack_core.c 2005-02-13 17:01:40.000000000 +0100
@@ -49,7 +49,7 @@
#include <linux/netfilter_ipv4/ip_conntrack_core.h>
#include <linux/netfilter_ipv4/listhelp.h>
-#define IP_CONNTRACK_VERSION "2.1"
+#define IP_CONNTRACK_VERSION "2.2"
#if 0
#define DEBUGP printk
@@ -65,7 +65,6 @@
void (*ip_conntrack_destroyed)(struct ip_conntrack *conntrack) = NULL;
LIST_HEAD(ip_conntrack_expect_list);
struct ip_conntrack_protocol *ip_ct_protos[MAX_IP_CT_PROTO];
-static LIST_HEAD(helpers);
unsigned int ip_conntrack_htable_size = 0;
int ip_conntrack_max;
struct list_head *ip_conntrack_hash;
@@ -73,7 +72,7 @@
static kmem_cache_t *ip_conntrack_expect_cachep;
struct ip_conntrack ip_conntrack_untracked;
unsigned int ip_ct_log_invalid;
-static LIST_HEAD(unconfirmed);
+LIST_HEAD(ip_conntrack_unconfirmed);
static int ip_conntrack_vmalloc;
DEFINE_PER_CPU(struct ip_conntrack_stat, ip_conntrack_stat);
@@ -137,7 +136,7 @@
/* ip_conntrack_expect helper functions */
-static void destroy_expect(struct ip_conntrack_expect *exp)
+void __ip_ct_destroy_expect(struct ip_conntrack_expect *exp)
{
ip_conntrack_put(exp->master);
IP_NF_ASSERT(!timer_pending(&exp->timeout));
@@ -145,7 +144,7 @@
CONNTRACK_STAT_INC(expect_delete);
}
-static void unlink_expect(struct ip_conntrack_expect *exp)
+void __ip_ct_unlink_expect(struct ip_conntrack_expect *exp)
{
MUST_BE_WRITE_LOCKED(&ip_conntrack_lock);
list_del(&exp->list);
@@ -158,9 +157,9 @@
struct ip_conntrack_expect *exp = (void *)ul_expect;
WRITE_LOCK(&ip_conntrack_lock);
- unlink_expect(exp);
+ __ip_ct_unlink_expect(exp);
WRITE_UNLOCK(&ip_conntrack_lock);
- destroy_expect(exp);
+ __ip_ct_destroy_expect(exp);
}
/* If an expectation for this connection is found, it gets delete from
@@ -179,7 +178,7 @@
if (ip_ct_tuple_mask_cmp(tuple, &i->tuple, &i->mask)
&& is_confirmed(i->master)
&& del_timer(&i->timeout)) {
- unlink_expect(i);
+ __ip_ct_unlink_expect(i);
return i;
}
}
@@ -197,8 +196,8 @@
list_for_each_entry_safe(i, tmp, &ip_conntrack_expect_list, list) {
if (i->master == ct && del_timer(&i->timeout)) {
- unlink_expect(i);
- destroy_expect(i);
+ __ip_ct_unlink_expect(i);
+ __ip_ct_destroy_expect(i);
}
}
}
@@ -439,19 +438,6 @@
return dropped;
}
-static inline int helper_cmp(const struct ip_conntrack_helper *i,
- const struct ip_conntrack_tuple *rtuple)
-{
- return ip_ct_tuple_mask_cmp(rtuple, &i->tuple, &i->mask);
-}
-
-static struct ip_conntrack_helper *ip_ct_find_helper(const struct ip_conntrack_tuple *tuple)
-{
- return LIST_FIND(&helpers, helper_cmp,
- struct ip_conntrack_helper *,
- tuple);
-}
-
/* Allocate a new conntrack: we return -ENOMEM if classification
failed due to stress. Otherwise it really is unclassifiable. */
static struct ip_conntrack_tuple_hash *
@@ -529,7 +515,8 @@
}
/* Overload tuple linked list to put us in unconfirmed list. */
- list_add(&conntrack->tuplehash[IP_CT_DIR_ORIGINAL].list, &unconfirmed);
+ list_add(&conntrack->tuplehash[IP_CT_DIR_ORIGINAL].list,
+ &ip_conntrack_unconfirmed);
atomic_inc(&ip_conntrack_count);
WRITE_UNLOCK(&ip_conntrack_lock);
@@ -537,7 +524,7 @@
if (exp) {
if (exp->expectfn)
exp->expectfn(conntrack, exp);
- destroy_expect(exp);
+ __ip_ct_destroy_expect(exp);
}
return &conntrack->tuplehash[IP_CT_DIR_ORIGINAL];
@@ -727,9 +714,9 @@
/* choose the the oldest expectation to evict */
list_for_each_entry_reverse(i, &ip_conntrack_expect_list, list) {
if (expect_matches(i, exp) && del_timer(&i->timeout)) {
- unlink_expect(i);
+ __ip_ct_unlink_expect(i);
WRITE_UNLOCK(&ip_conntrack_lock);
- destroy_expect(i);
+ __ip_ct_destroy_expect(i);
return;
}
}
@@ -781,8 +768,8 @@
list_for_each_entry_reverse(i, &ip_conntrack_expect_list, list) {
if (i->master == master) {
if (del_timer(&i->timeout)) {
- unlink_expect(i);
- destroy_expect(i);
+ __ip_ct_unlink_expect(i);
+ __ip_ct_destroy_expect(i);
}
break;
}
@@ -854,50 +841,6 @@
WRITE_UNLOCK(&ip_conntrack_lock);
}
-int ip_conntrack_helper_register(struct ip_conntrack_helper *me)
-{
- BUG_ON(me->timeout == 0);
- WRITE_LOCK(&ip_conntrack_lock);
- list_prepend(&helpers, me);
- WRITE_UNLOCK(&ip_conntrack_lock);
-
- return 0;
-}
-
-static inline int unhelp(struct ip_conntrack_tuple_hash *i,
- const struct ip_conntrack_helper *me)
-{
- if (tuplehash_to_ctrack(i)->helper == me)
- tuplehash_to_ctrack(i)->helper = NULL;
- return 0;
-}
-
-void ip_conntrack_helper_unregister(struct ip_conntrack_helper *me)
-{
- unsigned int i;
- struct ip_conntrack_expect *exp, *tmp;
-
- /* Need write lock here, to delete helper. */
- WRITE_LOCK(&ip_conntrack_lock);
- LIST_DELETE(&helpers, me);
-
- /* Get rid of expectations */
- list_for_each_entry_safe(exp, tmp, &ip_conntrack_expect_list, list) {
- if (exp->master->helper == me && del_timer(&exp->timeout)) {
- unlink_expect(exp);
- destroy_expect(exp);
- }
- }
- /* Get rid of expecteds, set helpers to NULL. */
- LIST_FIND_W(&unconfirmed, unhelp, struct ip_conntrack_tuple_hash*, me);
- for (i = 0; i < ip_conntrack_htable_size; i++)
- LIST_FIND_W(&ip_conntrack_hash[i], unhelp,
- struct ip_conntrack_tuple_hash *, me);
- WRITE_UNLOCK(&ip_conntrack_lock);
-
- /* Someone could be still looking at the helper in a bh. */
- synchronize_net();
-}
static inline void ct_add_counters(struct ip_conntrack *ct,
enum ip_conntrack_info ctinfo,
@@ -1017,7 +960,7 @@
break;
}
if (!h)
- h = LIST_FIND_W(&unconfirmed, do_iter,
+ h = LIST_FIND_W(&ip_conntrack_unconfirmed, do_iter,
struct ip_conntrack_tuple_hash *, iter, data);
if (h)
atomic_inc(&tuplehash_to_ctrack(h)->ct_general.use);
@@ -1141,6 +1084,7 @@
kmem_cache_destroy(ip_conntrack_expect_cachep);
free_conntrack_hash();
nf_unregister_sockopt(&so_getorigdst);
+ ip_conntrack_helper_fini();
}
static int hashsize;
@@ -1234,8 +1178,14 @@
/* - and look it like as a confirmed connection */
set_bit(IPS_CONFIRMED_BIT, &ip_conntrack_untracked.status);
+ ret = ip_conntrack_helper_init();
+ if (ret != 0)
+ goto err_free_exp_slab;
+
return ret;
+err_free_exp_slab:
+ kmem_cache_destroy(ip_conntrack_expect_cachep);
err_free_conntrack_slab:
kmem_cache_destroy(ip_conntrack_cachep);
err_free_hash:
diff -Nru --exclude .depend --exclude '*.o' --exclude '*.ko' --exclude '*.ver' --exclude '.*.flags' --exclude '*.orig' --exclude '*.rej' --exclude '*.cmd' --exclude '*.mod.c' --exclude '*~' linux-2.6.11-rc4/net/ipv4/netfilter/ip_conntrack_helper.c linux-2.6.11-rc4-helper_sysctl/net/ipv4/netfilter/ip_conntrack_helper.c
--- linux-2.6.11-rc4/net/ipv4/netfilter/ip_conntrack_helper.c 1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.11-rc4-helper_sysctl/net/ipv4/netfilter/ip_conntrack_helper.c 2005-02-13 17:46:42.000000000 +0100
@@ -0,0 +1,338 @@
+/* Dynamic conntrack helper to port binding
+ * (C) 2005 by Harald Welte <laforge@netfilter.org>
+ *
+ * Portions (C) 1999-2001 Paul `Rusty' Russell
+ * (C) 2002-2005 Netfilter Core Team <coreteam@netfilter.org>
+ *
+ * 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.
+ *
+ * 13 Feb 2005: Harald Welte <laforge@netfilter.org>
+ * - seperate out helper support from ip_conntrack_core
+ */
+
+#include <linux/module.h>
+#include <linux/config.h>
+#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
+
+#include <linux/skbuff.h>
+#include <linux/netdevice.h>
+
+#define ASSERT_READ_LOCK(x) MUST_BE_READ_LOCKED(&ip_conntrack_lock)
+#define ASSERT_WRITE_LOCK(x) MUST_BE_WRITE_LOCKED(&ip_conntrack_lock)
+
+#include <linux/netfilter_ipv4/listhelp.h>
+#include <linux/netfilter_ipv4/ip_conntrack.h>
+#include <linux/netfilter_ipv4/ip_conntrack_core.h>
+#include <linux/netfilter_ipv4/ip_conntrack_helper.h>
+
+static LIST_HEAD(helpers);
+static LIST_HEAD(helper_ports);
+
+struct helper_port {
+ struct list_head list;
+ struct ip_conntrack_helper *helper;
+ struct ip_conntrack_tuple tuple;
+};
+
+static struct helper_port *_hp_find_byport(struct ip_conntrack_helper *h,
+ u_int16_t port)
+{
+ struct helper_port *hp;
+
+ /* Must be locked under ip_conntrack_lock */
+ list_for_each_entry(hp, &helper_ports, list) {
+ if (hp->helper == h &&
+ hp->tuple.src.u.tcp.port == htons(port))
+ return hp;
+ }
+ return NULL;
+}
+
+int ip_conntrack_helper_add_port(struct ip_conntrack_helper *h, u_int16_t port)
+{
+ struct helper_port *hp;
+
+ hp = kmalloc(sizeof(*hp), GFP_KERNEL);
+ if (!hp)
+ return -ENOMEM;
+
+ /* Fill in the data */
+ hp->helper = h;
+ memcpy(&hp->tuple, &h->tuple, sizeof(struct ip_conntrack_tuple));
+ /* FIXME: this is a bit of a hack */
+ hp->tuple.src.u.tcp.port = htons(port);
+
+ WRITE_LOCK(&ip_conntrack_lock);
+
+ if (_hp_find_byport(h, port)) {
+ WRITE_UNLOCK(&ip_conntrack_lock);
+ kfree(hp);
+ return -EEXIST;
+ }
+
+ list_add(&hp->list, &helper_ports);
+
+ WRITE_UNLOCK(&ip_conntrack_lock);
+
+ return 0;
+}
+
+int ip_conntrack_helper_del_port(struct ip_conntrack_helper *h, u_int16_t port)
+{
+ struct helper_port *hp;
+
+ WRITE_LOCK(&ip_conntrack_lock);
+
+ hp = _hp_find_byport(h, port);
+
+ if (!hp) {
+ WRITE_UNLOCK(&ip_conntrack_lock);
+ return -ENODEV;
+ }
+
+ list_del(&hp->list);
+
+ WRITE_UNLOCK(&ip_conntrack_lock);
+
+ kfree(hp);
+
+ return 0;
+}
+
+#ifdef CONFIG_PROC_FS
+static struct proc_dir_entry *helper_procdir;
+
+static void *helper_seq_start(struct seq_file *s, loff_t *pos)
+{
+ struct proc_dir_entry *pde = s->private;
+ struct ip_conntrack_helper *h = pde->data;
+ struct helper_port *hp;
+ int i = 0;
+
+ /* strange seq_file aop calls stop even if start fails,
+ * thus we need to unconditionally grab the lock */
+ READ_LOCK(&ip_conntrack_lock);
+
+ if (list_empty(&helper_ports))
+ return NULL;
+
+ list_for_each_entry(hp, &helper_ports, list) {
+ if (hp->helper == h) {
+ if (i == *pos)
+ return hp;
+ i++;
+ }
+ }
+
+ return NULL;
+}
+
+static void *helper_seq_next(struct seq_file *s, void *v, loff_t *pos)
+{
+ struct proc_dir_entry *pde = s->private;
+ struct ip_conntrack_helper *h = pde->data;
+ struct helper_port *hp = v;
+
+ (*pos)++;
+ list_for_each_entry(hp, &hp->list, list) {
+ /* end traversal at list head */
+ if ((struct list_head *) hp == &helper_ports)
+ return NULL;
+ if (hp->helper == h) {
+ return hp;
+ }
+ }
+
+ return NULL;
+}
+
+static void helper_seq_stop(struct seq_file *s, void *v)
+{
+ READ_UNLOCK(&ip_conntrack_lock);
+}
+
+static int helper_seq_show(struct seq_file *s, void *v)
+{
+ struct helper_port *hp = v;
+
+ return seq_printf(s, "%u\n", ntohs(hp->tuple.src.u.tcp.port));
+}
+
+static struct seq_operations helper_seq_ops = {
+ .start = helper_seq_start,
+ .next = helper_seq_next,
+ .stop = helper_seq_stop,
+ .show = helper_seq_show,
+};
+
+static int helper_proc_open(struct inode *inode, struct file *file)
+{
+ int ret = seq_open(file, &helper_seq_ops);
+
+ if (!ret) {
+ struct seq_file *sf = file->private_data;
+ struct proc_dir_entry *pde = PDE(inode);
+
+ sf->private = pde;
+ /* FIXME: do we have to increase usage count ?*/
+ }
+
+ return ret;
+}
+
+static int helper_proc_release(struct inode *inode, struct file *file)
+{
+ int ret;
+
+ ret = seq_release(inode, file);
+
+ return ret;
+}
+
+static ssize_t helper_proc_write(struct file *file, const char __user *input,
+ size_t size, loff_t *ofs)
+{
+#define PROC_WRITELEN 10
+ char buffer[PROC_WRITELEN+1];
+ struct proc_dir_entry *pde = PDE(file->f_dentry->d_inode);
+ struct ip_conntrack_helper *h = pde->data;
+ unsigned long port;
+
+ if (copy_from_user(buffer, input, PROC_WRITELEN))
+ return -EFAULT;
+
+ if (*buffer == '+') {
+ port = simple_strtoul(buffer+1, NULL, 10);
+ if (ip_conntrack_helper_add_port(h, port))
+ return -EINVAL;
+ } else if (*buffer == '-') {
+ port = simple_strtoul(buffer+1, NULL, 10);
+ if (ip_conntrack_helper_del_port(h, port))
+ return -EINVAL;
+ } else
+ return -EIO;
+
+ return size;
+}
+
+static struct file_operations helper_proc_fops = {
+ .owner = THIS_MODULE,
+ .open = helper_proc_open,
+ .read = seq_read,
+ .write = helper_proc_write,
+ .llseek = seq_lseek,
+ .release = helper_proc_release,
+};
+
+#endif
+
+static inline int helper_cmp(const struct ip_conntrack_helper *i,
+ const struct ip_conntrack_tuple *rtuple)
+{
+ return ip_ct_tuple_mask_cmp(rtuple, &i->tuple, &i->mask);
+}
+
+struct ip_conntrack_helper *ip_ct_find_helper(const struct ip_conntrack_tuple *tuple)
+{
+ return LIST_FIND(&helpers, helper_cmp,
+ struct ip_conntrack_helper *,
+ tuple);
+}
+
+
+int ip_conntrack_helper_register(struct ip_conntrack_helper *me)
+{
+ BUG_ON(me->timeout == 0);
+
+
+ WRITE_LOCK(&ip_conntrack_lock);
+ list_prepend(&helpers, me);
+ WRITE_UNLOCK(&ip_conntrack_lock);
+
+#ifdef CONFIG_PROC_FS
+ me->pde = create_proc_entry(me->name, S_IWUSR|S_IRUSR, helper_procdir);
+ if (!me->pde)
+ return 1;
+ me->pde->proc_fops = &helper_proc_fops;
+ me->pde->data = me;
+#endif
+
+ return 0;
+}
+
+static inline int unhelp(struct ip_conntrack_tuple_hash *i,
+ const struct ip_conntrack_helper *me)
+{
+ if (tuplehash_to_ctrack(i)->helper == me)
+ tuplehash_to_ctrack(i)->helper = NULL;
+ return 0;
+}
+
+void ip_conntrack_helper_unregister(struct ip_conntrack_helper *me)
+{
+ unsigned int i;
+ struct ip_conntrack_expect *exp, *tmp;
+ struct helper_port *hp, *hp2;
+
+#ifdef CONFIG_PROC_FS
+ remove_proc_entry(me->pde->name, me->pde->parent);
+#endif
+
+ /* Need write lock here, to delete helper. */
+ WRITE_LOCK(&ip_conntrack_lock);
+
+ /* First delete us from global list of helpers */
+ LIST_DELETE(&helpers, me);
+
+ /* Then delete us from helper_ports */
+ list_for_each_entry_safe(hp, hp2, &helper_ports, list) {
+ if (hp->helper == me) {
+ list_del(&hp->list);
+ kfree(hp);
+ }
+ }
+
+ /* Get rid of expectations */
+ list_for_each_entry_safe(exp, tmp, &ip_conntrack_expect_list, list) {
+ if (exp->master->helper == me && del_timer(&exp->timeout)) {
+ __ip_ct_unlink_expect(exp);
+ __ip_ct_destroy_expect(exp);
+ }
+ }
+ /* Get rid of expecteds, set helpers to NULL. */
+ LIST_FIND_W(&ip_conntrack_unconfirmed,
+ unhelp, struct ip_conntrack_tuple_hash*, me);
+ for (i = 0; i < ip_conntrack_htable_size; i++)
+ LIST_FIND_W(&ip_conntrack_hash[i], unhelp,
+ struct ip_conntrack_tuple_hash *, me);
+ WRITE_UNLOCK(&ip_conntrack_lock);
+
+ /* Someone could be still looking at the helper in a bh. */
+ synchronize_net();
+}
+
+int ip_conntrack_helper_init(void)
+{
+#ifdef CONFIG_PROC_FS
+ helper_procdir = proc_mkdir("ip_conntrack_helper", proc_net);
+ if (!helper_procdir) {
+ printk(KERN_ERR "ip_conntrack_helper: unable to create proc\n");
+ return -ENOMEM;
+ }
+#endif
+
+ return 0;
+}
+
+void ip_conntrack_helper_fini(void)
+{
+#ifdef CONFIG_PROC_FS
+ remove_proc_entry(helper_procdir->name, helper_procdir->parent);
+#endif
+}
+
+EXPORT_SYMBOL(ip_conntrack_helper_add_port);
+EXPORT_SYMBOL(ip_conntrack_helper_del_port);
diff -Nru --exclude .depend --exclude '*.o' --exclude '*.ko' --exclude '*.ver' --exclude '.*.flags' --exclude '*.orig' --exclude '*.rej' --exclude '*.cmd' --exclude '*.mod.c' --exclude '*~' linux-2.6.11-rc4/net/ipv4/netfilter/ip_conntrack_standalone.c linux-2.6.11-rc4-helper_sysctl/net/ipv4/netfilter/ip_conntrack_standalone.c
--- linux-2.6.11-rc4/net/ipv4/netfilter/ip_conntrack_standalone.c 2005-02-13 13:52:06.000000000 +0100
+++ linux-2.6.11-rc4-helper_sysctl/net/ipv4/netfilter/ip_conntrack_standalone.c 2005-02-13 16:14:26.000000000 +0100
@@ -918,3 +918,6 @@
#ifdef CONFIG_IP_NF_NAT_NEEDED
EXPORT_SYMBOL(ip_conntrack_tcp_update);
#endif
+EXPORT_SYMBOL(__ip_ct_unlink_expect);
+EXPORT_SYMBOL(__ip_ct_destroy_expect);
+EXPORT_SYMBOL(ip_conntrack_unconfirmed);
[-- Attachment #1.3: 2.6.11-rc4-ip_conntrack_helper_proc-helpers.patch --]
[-- Type: text/plain, Size: 8025 bytes --]
diff -Nru --exclude .depend --exclude '*.o' --exclude '*.ko' --exclude '*.ver' --exclude '.*.flags' --exclude '*.orig' --exclude '*.rej' --exclude '*.cmd' --exclude '*.mod.c' --exclude '*~' linux-2.6.11-rc4/net/ipv4/netfilter/ip_conntrack_ftp.c linux-2.6.11-rc4-helper_sysctl/net/ipv4/netfilter/ip_conntrack_ftp.c
--- linux-2.6.11-rc4/net/ipv4/netfilter/ip_conntrack_ftp.c 2005-02-13 13:52:06.000000000 +0100
+++ linux-2.6.11-rc4-helper_sysctl/net/ipv4/netfilter/ip_conntrack_ftp.c 2005-02-13 17:39:03.000000000 +0100
@@ -1,7 +1,7 @@
/* FTP extension for IP connection tracking. */
/* (C) 1999-2001 Paul `Rusty' Russell
- * (C) 2002-2004 Netfilter Core Team <coreteam@netfilter.org>
+ * (C) 2002-2005 Netfilter Core Team <coreteam@netfilter.org>
*
* 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
@@ -446,48 +446,43 @@
return ret;
}
-static struct ip_conntrack_helper ftp[MAX_PORTS];
-static char ftp_names[MAX_PORTS][10];
+static struct ip_conntrack_helper ftp = {
+ .name = "ftp",
+ .help = &help,
+ .me = THIS_MODULE,
+ .timeout = 5 * 60, /* 5 minutes */
+ .max_expected = 1,
+ .mask = {
+ .dst.protonum = 0xff,
+ .src.u.tcp.port = 0xffff,
+ },
+ .tuple = {
+ .dst.protonum = IPPROTO_TCP,
+ .src.u.tcp.port = __constant_htons(21),
+ },
+};
/* Not __exit: called from init() */
static void fini(void)
{
- int i;
- for (i = 0; i < ports_c; i++) {
- DEBUGP("ip_ct_ftp: unregistering helper for port %d\n",
- ports[i]);
- ip_conntrack_helper_unregister(&ftp[i]);
- }
+ ip_conntrack_helper_unregister(&ftp);
}
static int __init init(void)
{
int i, ret;
- char *tmpname;
- if (ports_c == 0)
- ports[ports_c++] = FTP_PORT;
+ if (ports_c == 0) {
+ ports[0] = 21;
+ ports_c = 1;
+ }
+
+ ret = ip_conntrack_helper_register(&ftp);
for (i = 0; i < ports_c; i++) {
- ftp[i].tuple.src.u.tcp.port = htons(ports[i]);
- ftp[i].tuple.dst.protonum = IPPROTO_TCP;
- ftp[i].mask.src.u.tcp.port = 0xFFFF;
- ftp[i].mask.dst.protonum = 0xFF;
- ftp[i].max_expected = 1;
- ftp[i].timeout = 5 * 60; /* 5 minutes */
- ftp[i].me = THIS_MODULE;
- ftp[i].help = help;
-
- tmpname = &ftp_names[i][0];
- if (ports[i] == FTP_PORT)
- sprintf(tmpname, "ftp");
- else
- sprintf(tmpname, "ftp-%d", ports[i]);
- ftp[i].name = tmpname;
-
DEBUGP("ip_ct_ftp: registering helper for port %d\n",
ports[i]);
- ret = ip_conntrack_helper_register(&ftp[i]);
+ ret = ip_conntrack_helper_add_port(&ftp, ports[i]);
if (ret) {
fini();
diff -Nru --exclude .depend --exclude '*.o' --exclude '*.ko' --exclude '*.ver' --exclude '.*.flags' --exclude '*.orig' --exclude '*.rej' --exclude '*.cmd' --exclude '*.mod.c' --exclude '*~' linux-2.6.11-rc4/net/ipv4/netfilter/ip_conntrack_irc.c linux-2.6.11-rc4-helper_sysctl/net/ipv4/netfilter/ip_conntrack_irc.c
--- linux-2.6.11-rc4/net/ipv4/netfilter/ip_conntrack_irc.c 2005-02-13 13:52:06.000000000 +0100
+++ linux-2.6.11-rc4-helper_sysctl/net/ipv4/netfilter/ip_conntrack_irc.c 2005-02-13 17:39:29.000000000 +0100
@@ -1,5 +1,5 @@
/* IRC extension for IP connection tracking, Version 1.21
- * (C) 2000-2002 by Harald Welte <laforge@gnumonks.org>
+ * (C) 2000-2005 by Harald Welte <laforge@gnumonks.org>
* based on RR's ip_conntrack_ftp.c
*
* ip_conntrack_irc.c,v 1.21 2002/02/05 14:49:26 laforge Exp
@@ -241,16 +241,25 @@
return ret;
}
-static struct ip_conntrack_helper irc_helpers[MAX_PORTS];
-static char irc_names[MAX_PORTS][10];
+static struct ip_conntrack_helper irc_helper = {
+ .name = "irc",
+ .help = &help,
+ .me = THIS_MODULE,
+ .mask = {
+ .dst.protonum = 0xff,
+ .src.u.tcp.port = 0xffff,
+ },
+ .tuple = {
+ .dst.protonum = IPPROTO_TCP,
+ .src.u.tcp.port = __constant_htons(6667),
+ },
+};
static void fini(void);
static int __init init(void)
{
int i, ret;
- struct ip_conntrack_helper *hlpr;
- char *tmpname;
if (max_dcc_channels < 1) {
printk("ip_conntrack_irc: max_dcc_channels must be a positive integer\n");
@@ -260,32 +269,19 @@
printk("ip_conntrack_irc: dcc_timeout must be a positive integer\n");
return -EBUSY;
}
-
- /* If no port given, default to standard irc port */
- if (ports_c == 0)
- ports[ports_c++] = IRC_PORT;
- for (i = 0; i < ports_c; i++) {
- hlpr = &irc_helpers[i];
- hlpr->tuple.src.u.tcp.port = htons(ports[i]);
- hlpr->tuple.dst.protonum = IPPROTO_TCP;
- hlpr->mask.src.u.tcp.port = 0xFFFF;
- hlpr->mask.dst.protonum = 0xFF;
- hlpr->max_expected = max_dcc_channels;
- hlpr->timeout = dcc_timeout;
- hlpr->me = THIS_MODULE;
- hlpr->help = help;
-
- tmpname = &irc_names[i][0];
- if (ports[i] == IRC_PORT)
- sprintf(tmpname, "irc");
- else
- sprintf(tmpname, "irc-%d", i);
- hlpr->name = tmpname;
+ irc_helper.timeout = dcc_timeout;
+ irc_helper.max_expected = max_dcc_channels;
+
+ if (ports_c == 0) {
+ ports[0] = 6667;
+ ports_c = 1;
+ }
- DEBUGP("port #%d: %d\n", i, ports[i]);
+ ret = ip_conntrack_helper_register(&irc_helper);
- ret = ip_conntrack_helper_register(hlpr);
+ for (i = 0; i < ports_c; i++) {
+ ret = ip_conntrack_helper_add_port(&irc_helper, ports[i]);
if (ret) {
printk("ip_conntrack_irc: ERROR registering port %d\n",
@@ -301,12 +297,7 @@
* it is needed by the init function */
static void fini(void)
{
- int i;
- for (i = 0; i < ports_c; i++) {
- DEBUGP("unregistering port %d\n",
- ports[i]);
- ip_conntrack_helper_unregister(&irc_helpers[i]);
- }
+ ip_conntrack_helper_unregister(&irc_helper);
}
module_init(init);
diff -Nru --exclude .depend --exclude '*.o' --exclude '*.ko' --exclude '*.ver' --exclude '.*.flags' --exclude '*.orig' --exclude '*.rej' --exclude '*.cmd' --exclude '*.mod.c' --exclude '*~' linux-2.6.11-rc4/net/ipv4/netfilter/ip_conntrack_tftp.c linux-2.6.11-rc4-helper_sysctl/net/ipv4/netfilter/ip_conntrack_tftp.c
--- linux-2.6.11-rc4/net/ipv4/netfilter/ip_conntrack_tftp.c 2005-02-13 13:52:06.000000000 +0100
+++ linux-2.6.11-rc4-helper_sysctl/net/ipv4/netfilter/ip_conntrack_tftp.c 2005-02-13 17:44:55.000000000 +0100
@@ -100,51 +100,38 @@
return NF_ACCEPT;
}
-static struct ip_conntrack_helper tftp[MAX_PORTS];
-static char tftp_names[MAX_PORTS][10];
+static struct ip_conntrack_helper tftp_helper = {
+ .name = "tftp",
+ .help = &tftp_help,
+ .me = THIS_MODULE,
+ .timeout = 5 * 60, /* 5 minutes */
+ .max_expected = 1,
+ .mask = {
+ .src.u.udp.port = 0xffff,
+ .dst.protonum = 0xff,
+ },
+ .tuple = {
+ .src.u.udp.port = TFTP_PORT,
+ .dst.protonum = IPPROTO_UDP,
+ },
+};
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(&tftp[i]);
- }
+ ip_conntrack_helper_unregister(&tftp_helper);
}
static int __init init(void)
{
int i, ret;
- char *tmpname;
if (ports_c == 0)
ports[ports_c++] = TFTP_PORT;
for (i = 0; i < ports_c; i++) {
- /* Create helper structure */
- memset(&tftp[i], 0, sizeof(struct ip_conntrack_helper));
-
- tftp[i].tuple.dst.protonum = IPPROTO_UDP;
- tftp[i].tuple.src.u.udp.port = htons(ports[i]);
- tftp[i].mask.dst.protonum = 0xFF;
- tftp[i].mask.src.u.udp.port = 0xFFFF;
- tftp[i].max_expected = 1;
- tftp[i].timeout = 5 * 60; /* 5 minutes */
- tftp[i].me = THIS_MODULE;
- tftp[i].help = tftp_help;
-
- tmpname = &tftp_names[i][0];
- if (ports[i] == TFTP_PORT)
- sprintf(tmpname, "tftp");
- else
- sprintf(tmpname, "tftp-%d", i);
- tftp[i].name = tmpname;
-
DEBUGP("port #%d: %d\n", i, ports[i]);
- ret=ip_conntrack_helper_register(&tftp[i]);
+ ret = ip_conntrack_helper_add_port(&tftp_helper, ports[i]);
if (ret) {
printk("ERROR registering helper for port %d\n",
ports[i]);
[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 189 bytes --]
^ permalink raw reply [flat|nested] 6+ messages in thread* Re: [PATCH 2.6] Allow dynamic helper-port assignment
2005-02-13 16:56 [PATCH 2.6] Allow dynamic helper-port assignment Harald Welte
@ 2005-02-13 17:34 ` Max Kellermann
2005-02-13 22:38 ` Jozsef Kadlecsik
2005-02-14 11:59 ` Martijn Lievaart
2 siblings, 0 replies; 6+ messages in thread
From: Max Kellermann @ 2005-02-13 17:34 UTC (permalink / raw)
To: netfilter-devel
On 2005/02/13 17:56, Harald Welte <laforge@netfilter.org> wrote:
> Ideally, we would actually have conntrack helpers be iptables targets,
> this way allowing totally dynamic assignemnt. Maybe yet another
> pkttables todo.
Good idea.
The downside is, to use a helper, you have to explicitly configure
it. That is so easy currently - add the helper to the kernel, and it
just works (on the default ports, that is). But that's ok for me.
> Meanwhile, the following patch uses the same mechanism as CLUSTERIP:
>
> Add port 2121 to ftp helper:
> echo "+2121" > /proc/net/ip_conntrack_helper/ftp
>
> Remove port 6669 from irc helper:
> echo "-6669" > /proc/net/ip_conntrack_helper/irc
>
> Show registered ports for amanda helper:
> cat /proc/net/ip_conntrack_helper/amanda
Why don't you use the existing /sys/module/XX/parameters/YY interface?
That includes static modules. We could even use a custom setter
function for the "port" property.
cat /sys/module/ip_conntrack_irc/parameters/ports
That already works, it's just not writable (yet).
> If nobody complains, we should push this for 2.6.12.
*complain*
Why push a solution which will go away soon anyway to the mainstream
kernel? When people understand how to use that change, it's already
gone.
Max
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH 2.6] Allow dynamic helper-port assignment
2005-02-13 16:56 [PATCH 2.6] Allow dynamic helper-port assignment Harald Welte
2005-02-13 17:34 ` Max Kellermann
@ 2005-02-13 22:38 ` Jozsef Kadlecsik
2005-02-14 11:21 ` Harald Welte
2005-02-14 11:59 ` Martijn Lievaart
2 siblings, 1 reply; 6+ messages in thread
From: Jozsef Kadlecsik @ 2005-02-13 22:38 UTC (permalink / raw)
To: Harald Welte; +Cc: Netfilter Development Mailinglist
Hi Harald,
On Sun, 13 Feb 2005, Harald Welte wrote:
> The recent problem with h323 made me again consider the old idea of
> having runtime-configurable port assignments for helpers.
>
> Ideally, we would actually have conntrack helpers be iptables targets,
> this way allowing totally dynamic assignemnt. Maybe yet another
> pkttables todo.
>
> Meanwhile, the following patch uses the same mechanism as CLUSTERIP:
>
> Add port 2121 to ftp helper:
> echo "+2121" > /proc/net/ip_conntrack_helper/ftp
>
> Remove port 6669 from irc helper:
> echo "-6669" > /proc/net/ip_conntrack_helper/irc
Let's imagine a real H.323 helper module, which works reliably (contrary
to the current one) and thus deployed at sites which use videoconferencing
heavily. Due to the nature of H.323, the dynamic H.245 helpers are truly
created dynamically for every single H.225 session, which starts the whole
H.323 protocol-tree . The currently nicely static helper list (which we
could thus protect even by RCU locking) would become dynamic and
could create *potentially* a new bottleneck.
Let's assume another protocol, which uses dynamic sub-helpers. How
could we handle the possible ports clashes of the different
sub-helpers in your scheme?
Best regards,
Jozsef
-
E-mail : kadlec@blackhole.kfki.hu, kadlec@sunserv.kfki.hu
PGP key : http://www.kfki.hu/~kadlec/pgp_public_key.txt
Address : KFKI Research Institute for Particle and Nuclear Physics
H-1525 Budapest 114, POB. 49, Hungary
^ permalink raw reply [flat|nested] 6+ messages in thread* Re: [PATCH 2.6] Allow dynamic helper-port assignment
2005-02-13 22:38 ` Jozsef Kadlecsik
@ 2005-02-14 11:21 ` Harald Welte
0 siblings, 0 replies; 6+ messages in thread
From: Harald Welte @ 2005-02-14 11:21 UTC (permalink / raw)
To: Jozsef Kadlecsik; +Cc: Netfilter Development Mailinglist
[-- Attachment #1: Type: text/plain, Size: 2084 bytes --]
On Sun, Feb 13, 2005 at 11:38:40PM +0100, Jozsef Kadlecsik wrote:
> Hi Harald,
>
> Let's imagine a real H.323 helper module, which works reliably (contrary
> to the current one) and thus deployed at sites which use videoconferencing
> heavily. Due to the nature of H.323, the dynamic H.245 helpers are truly
> created dynamically for every single H.225 session, which starts the whole
> H.323 protocol-tree . The currently nicely static helper list (which we
> could thus protect even by RCU locking) would become dynamic and
> could create *potentially* a new bottleneck.
Well, while h323 triggered my work on dynamic helper-port assignment, it
is not really proposed as a solution to the h323 problem. It merely
solves the h323-oops problem as a side-effect, since it (again, as a
side effect) splits helper registration and port assignment in two
seperate steps.
The helper list could indeed become a bottleneck, but unless you run in
front of a heavily loaded h323 pbx I don't think that's much of an issue
now.
My patch clearly seperates helper lookup from the conntrack core, thus
enabling implementation of faster matching algorithms
> Let's assume another protocol, which uses dynamic sub-helpers. How
> could we handle the possible ports clashes of the different
> sub-helpers in your scheme?
That's a totally different problem. Actually two:
1) helpers register overlapping expectations.
most likely the helpers are broken, and/or they need nat reservations
(which we ought to provide)
2) helpers expectations overlap with administrator-assigned ports
Well, the admin can alway shoot himself in the foot. No action
required here.
> Jozsef
--
- Harald Welte <laforge@netfilter.org> http://www.netfilter.org/
============================================================================
"Fragmentation is like classful addressing -- an interesting early
architectural error that shows how much experimentation was going
on while IP was being designed." -- Paul Vixie
[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 189 bytes --]
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH 2.6] Allow dynamic helper-port assignment
2005-02-13 16:56 [PATCH 2.6] Allow dynamic helper-port assignment Harald Welte
2005-02-13 17:34 ` Max Kellermann
2005-02-13 22:38 ` Jozsef Kadlecsik
@ 2005-02-14 11:59 ` Martijn Lievaart
2005-02-14 12:20 ` Martijn Lievaart
2 siblings, 1 reply; 6+ messages in thread
From: Martijn Lievaart @ 2005-02-14 11:59 UTC (permalink / raw)
To: Harald Welte; +Cc: Netfilter Development Mailinglist
Harald Welte wrote:
>Hi!
>
>The recent problem with h323 made me again consider the old idea of
>having runtime-configurable port assignments for helpers.
>
>Ideally, we would actually have conntrack helpers be iptables targets,
>this way allowing totally dynamic assignemnt. Maybe yet another
>pkttables todo.
>
>
I've already been thinking about this before you mentioned it. Here's
one way it could be done.
If a helper is loaded with the argument "noauto" (f.i.) it does not
register the default ports, otherwise it does. This keeps backward
compatibility, does what you want in general, but still gives a way out
for those people who run ssh over port 21.
Additional ports can be registered with a target, f.i. "-p tcp -p 666 -s
<someip> -j HELP --helper ftp". This would add a helper for this
specific connection. Obviously, people that load modules with noauto
need to help all connections themselves.
Pro:
+ Backward compatible
+ In general does the right thing while also allowing all flexibilty one
could want.
Con:
- Looks like a lot of work to implement.
- Increases size of contrack structure? Can use that new contack
extension thingy introduced lately if this crops up.
I already looked at the source to see if it was feasable, but decided it
was a bit to much for me.
M4
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH 2.6] Allow dynamic helper-port assignment
2005-02-14 11:59 ` Martijn Lievaart
@ 2005-02-14 12:20 ` Martijn Lievaart
0 siblings, 0 replies; 6+ messages in thread
From: Martijn Lievaart @ 2005-02-14 12:20 UTC (permalink / raw)
To: Netfilter Development Mailinglist; +Cc: Harald Welte
Martijn Lievaart wrote:
> Additional ports can be registered with a target, f.i. "-p tcp -p 666
> -s <someip> -j HELP --helper ftp". This would add a helper for this
> specific connection. Obviously, people that load modules with
Raaah. Engage brain before typing.
s/-p 666/--dport 666/
M4
^ permalink raw reply [flat|nested] 6+ messages in thread
end of thread, other threads:[~2005-02-14 12:20 UTC | newest]
Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2005-02-13 16:56 [PATCH 2.6] Allow dynamic helper-port assignment Harald Welte
2005-02-13 17:34 ` Max Kellermann
2005-02-13 22:38 ` Jozsef Kadlecsik
2005-02-14 11:21 ` Harald Welte
2005-02-14 11:59 ` Martijn Lievaart
2005-02-14 12:20 ` Martijn Lievaart
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.