From 0379e92f17e62738fb7fc3c94830d18b792e92b2 Mon Sep 17 00:00:00 2001 From: Jozsef Kadlecsik Date: Thu, 2 Oct 2003 09:21:29 -0700 Subject: [PATCH] [NETFILTER]: Make conntrack timeouts become sysctls. This patch introduces the /proc/sys/net/ipv4/netfilter/ directory for=20 the tuneable parameters of the conntrack engine of netfilter. The parameters which can currently be fine-tuned (if required at all)=20 are the ip_conntrack_max, and the conntrack timeout parameters in seconds. The default timeout value for the TCP CLOSE_WAIT state is raised to 3 days, which should cause less problems with long-lived half-closed TCP sessions. For the sake of compatibility with 2.4,=20 /proc/sys/net/ipv4/netfilter/ip_conntrack_max is duplicated as=20 /proc/sys/net/ipv4/ip_conntrack_max as well. --- net/ipv4/netfilter/ip_conntrack_core.c | 59 +--------- .../netfilter/ip_conntrack_proto_generic.c | 4 +- net/ipv4/netfilter/ip_conntrack_proto_icmp.c | 4 +- net/ipv4/netfilter/ip_conntrack_proto_tcp.c | 38 ++++--- net/ipv4/netfilter/ip_conntrack_proto_udp.c | 8 +- net/ipv4/netfilter/ip_conntrack_standalone.c | 106 ++++++++++++++++++ 6 files changed, 138 insertions(+), 81 deletions(-) diff --git a/net/ipv4/netfilter/ip_conntrack_core.c b/net/ipv4/netfilter/ip_conntrack_core.c index ae3f5db679b6c..02630aedef4e7 100644 --- a/net/ipv4/netfilter/ip_conntrack_core.c +++ b/net/ipv4/netfilter/ip_conntrack_core.c @@ -59,7 +59,7 @@ LIST_HEAD(ip_conntrack_expect_list); LIST_HEAD(protocol_list); static LIST_HEAD(helpers); unsigned int ip_conntrack_htable_size = 0; -static int ip_conntrack_max; +int ip_conntrack_max; static atomic_t ip_conntrack_count = ATOMIC_INIT(0); struct list_head *ip_conntrack_hash; static kmem_cache_t *ip_conntrack_cachep; @@ -1328,45 +1328,6 @@ static struct nf_sockopt_ops so_getorigdst = { .get = &getorigdst, }; -#define NET_IP_CONNTRACK_MAX 2089 -#define NET_IP_CONNTRACK_MAX_NAME "ip_conntrack_max" - -#ifdef CONFIG_SYSCTL -static struct ctl_table_header *ip_conntrack_sysctl_header; - -static ctl_table ip_conntrack_table[] = { - { - .ctl_name = NET_IP_CONNTRACK_MAX, - .procname = NET_IP_CONNTRACK_MAX_NAME, - .data = &ip_conntrack_max, - .maxlen = sizeof(ip_conntrack_max), - .mode = 0644, - .proc_handler = proc_dointvec - }, - { .ctl_name = 0 } -}; - -static ctl_table ip_conntrack_dir_table[] = { - { - .ctl_name = NET_IPV4, - .procname = "ipv4", - .mode = 0555, - .child = ip_conntrack_table - }, - { .ctl_name = 0 } -}; - -static ctl_table ip_conntrack_root_table[] = { - { - .ctl_name = CTL_NET, - .procname = "net", - .mode = 0555, - .child = ip_conntrack_dir_table - }, - { .ctl_name = 0 } -}; -#endif /*CONFIG_SYSCTL*/ - static int kill_all(const struct ip_conntrack *i, void *data) { return 1; @@ -1376,9 +1337,6 @@ static int kill_all(const struct ip_conntrack *i, void *data) supposed to kill the mall. */ void ip_conntrack_cleanup(void) { -#ifdef CONFIG_SYSCTL - unregister_sysctl_table(ip_conntrack_sysctl_header); -#endif ip_ct_attach = NULL; /* This makes sure all current packets have passed through netfilter framework. Roll on, two-stage module @@ -1456,25 +1414,10 @@ int __init ip_conntrack_init(void) for (i = 0; i < ip_conntrack_htable_size; i++) INIT_LIST_HEAD(&ip_conntrack_hash[i]); -/* This is fucking braindead. There is NO WAY of doing this without - the CONFIG_SYSCTL unless you don't want to detect errors. - Grrr... --RR */ -#ifdef CONFIG_SYSCTL - ip_conntrack_sysctl_header - = register_sysctl_table(ip_conntrack_root_table, 0); - if (ip_conntrack_sysctl_header == NULL) { - goto err_free_ct_cachep; - } -#endif /*CONFIG_SYSCTL*/ - /* For use by ipt_REJECT */ ip_ct_attach = ip_conntrack_attach; return ret; -#ifdef CONFIG_SYSCTL -err_free_ct_cachep: - kmem_cache_destroy(ip_conntrack_cachep); -#endif /*CONFIG_SYSCTL*/ err_free_hash: vfree(ip_conntrack_hash); err_unreg_sockopt: diff --git a/net/ipv4/netfilter/ip_conntrack_proto_generic.c b/net/ipv4/netfilter/ip_conntrack_proto_generic.c index 74768998bd105..4a4dddaea89cb 100644 --- a/net/ipv4/netfilter/ip_conntrack_proto_generic.c +++ b/net/ipv4/netfilter/ip_conntrack_proto_generic.c @@ -4,7 +4,7 @@ #include #include -#define GENERIC_TIMEOUT (600*HZ) +unsigned long ip_ct_generic_timeout = 600*HZ; static int generic_pkt_to_tuple(const struct sk_buff *skb, unsigned int dataoff, @@ -44,7 +44,7 @@ static int packet(struct ip_conntrack *conntrack, const struct sk_buff *skb, enum ip_conntrack_info conntrackinfo) { - ip_ct_refresh(conntrack, GENERIC_TIMEOUT); + ip_ct_refresh(conntrack, ip_ct_generic_timeout); return NF_ACCEPT; } diff --git a/net/ipv4/netfilter/ip_conntrack_proto_icmp.c b/net/ipv4/netfilter/ip_conntrack_proto_icmp.c index e280eeba49a81..409c0781dc20b 100644 --- a/net/ipv4/netfilter/ip_conntrack_proto_icmp.c +++ b/net/ipv4/netfilter/ip_conntrack_proto_icmp.c @@ -6,7 +6,7 @@ #include #include -#define ICMP_TIMEOUT (30*HZ) +unsigned long ip_ct_icmp_timeout = 30*HZ; #if 0 #define DEBUGP printk @@ -86,7 +86,7 @@ static int icmp_packet(struct ip_conntrack *ct, ct->timeout.function((unsigned long)ct); } else { atomic_inc(&ct->proto.icmp.count); - ip_ct_refresh(ct, ICMP_TIMEOUT); + ip_ct_refresh(ct, ip_ct_icmp_timeout); } return NF_ACCEPT; diff --git a/net/ipv4/netfilter/ip_conntrack_proto_tcp.c b/net/ipv4/netfilter/ip_conntrack_proto_tcp.c index 37e478dfb81f8..0e76daa586a53 100644 --- a/net/ipv4/netfilter/ip_conntrack_proto_tcp.c +++ b/net/ipv4/netfilter/ip_conntrack_proto_tcp.c @@ -49,20 +49,28 @@ static const char *tcp_conntrack_names[] = { #define HOURS * 60 MINS #define DAYS * 24 HOURS - -static unsigned long tcp_timeouts[] -= { 30 MINS, /* TCP_CONNTRACK_NONE, */ - 5 DAYS, /* TCP_CONNTRACK_ESTABLISHED, */ - 2 MINS, /* TCP_CONNTRACK_SYN_SENT, */ - 60 SECS, /* TCP_CONNTRACK_SYN_RECV, */ - 2 MINS, /* TCP_CONNTRACK_FIN_WAIT, */ - 2 MINS, /* TCP_CONNTRACK_TIME_WAIT, */ - 10 SECS, /* TCP_CONNTRACK_CLOSE, */ - 60 SECS, /* TCP_CONNTRACK_CLOSE_WAIT, */ - 30 SECS, /* TCP_CONNTRACK_LAST_ACK, */ - 2 MINS, /* TCP_CONNTRACK_LISTEN, */ -}; - +unsigned long ip_ct_tcp_timeout_syn_sent = 2 MINS; +unsigned long ip_ct_tcp_timeout_syn_recv = 60 SECS; +unsigned long ip_ct_tcp_timeout_established = 5 DAYS; +unsigned long ip_ct_tcp_timeout_fin_wait = 2 MINS; +unsigned long ip_ct_tcp_timeout_close_wait = 3 DAYS; +unsigned long ip_ct_tcp_timeout_last_ack = 30 SECS; +unsigned long ip_ct_tcp_timeout_time_wait = 2 MINS; +unsigned long ip_ct_tcp_timeout_close = 10 SECS; + +static unsigned long * tcp_timeouts[] += { 0, /* TCP_CONNTRACK_NONE */ + &ip_ct_tcp_timeout_established, /* TCP_CONNTRACK_ESTABLISHED, */ + &ip_ct_tcp_timeout_syn_sent, /* TCP_CONNTRACK_SYN_SENT, */ + &ip_ct_tcp_timeout_syn_recv, /* TCP_CONNTRACK_SYN_RECV, */ + &ip_ct_tcp_timeout_fin_wait, /* TCP_CONNTRACK_FIN_WAIT, */ + &ip_ct_tcp_timeout_time_wait, /* TCP_CONNTRACK_TIME_WAIT, */ + &ip_ct_tcp_timeout_close, /* TCP_CONNTRACK_CLOSE, */ + &ip_ct_tcp_timeout_close_wait, /* TCP_CONNTRACK_CLOSE_WAIT, */ + &ip_ct_tcp_timeout_last_ack, /* TCP_CONNTRACK_LAST_ACK, */ + 0, /* TCP_CONNTRACK_LISTEN */ + }; + #define sNO TCP_CONNTRACK_NONE #define sES TCP_CONNTRACK_ESTABLISHED #define sSS TCP_CONNTRACK_SYN_SENT @@ -204,7 +212,7 @@ static int tcp_packet(struct ip_conntrack *conntrack, set_bit(IPS_ASSURED_BIT, &conntrack->status); WRITE_UNLOCK(&tcp_lock); - ip_ct_refresh(conntrack, tcp_timeouts[newconntrack]); + ip_ct_refresh(conntrack, *tcp_timeouts[newconntrack]); } return NF_ACCEPT; diff --git a/net/ipv4/netfilter/ip_conntrack_proto_udp.c b/net/ipv4/netfilter/ip_conntrack_proto_udp.c index 120f2c38e1a19..f560174d22794 100644 --- a/net/ipv4/netfilter/ip_conntrack_proto_udp.c +++ b/net/ipv4/netfilter/ip_conntrack_proto_udp.c @@ -6,8 +6,8 @@ #include #include -#define UDP_TIMEOUT (30*HZ) -#define UDP_STREAM_TIMEOUT (180*HZ) +unsigned long ip_ct_udp_timeout = 30*HZ; +unsigned long ip_ct_udp_timeout_stream = 180*HZ; static int udp_pkt_to_tuple(const struct sk_buff *skb, unsigned int dataoff, @@ -57,11 +57,11 @@ static int udp_packet(struct ip_conntrack *conntrack, /* If we've seen traffic both ways, this is some kind of UDP stream. Extend timeout. */ if (test_bit(IPS_SEEN_REPLY_BIT, &conntrack->status)) { - ip_ct_refresh(conntrack, UDP_STREAM_TIMEOUT); + ip_ct_refresh(conntrack, ip_ct_udp_timeout_stream); /* Also, more likely to be important, and not a probe */ set_bit(IPS_ASSURED_BIT, &conntrack->status); } else - ip_ct_refresh(conntrack, UDP_TIMEOUT); + ip_ct_refresh(conntrack, ip_ct_udp_timeout); return NF_ACCEPT; } diff --git a/net/ipv4/netfilter/ip_conntrack_standalone.c b/net/ipv4/netfilter/ip_conntrack_standalone.c index 6dc8fd2a065be..62c3ea2e5dd83 100644 --- a/net/ipv4/netfilter/ip_conntrack_standalone.c +++ b/net/ipv4/netfilter/ip_conntrack_standalone.c @@ -7,6 +7,7 @@ /* (c) 1999 Paul `Rusty' Russell. Licenced under the GNU General Public Licence. */ +#include #include #include #include @@ -14,6 +15,9 @@ #include #include #include +#ifdef CONFIG_SYSCTL +#include +#endif #include #define ASSERT_READ_LOCK(x) MUST_BE_READ_LOCKED(&ip_conntrack_lock) @@ -256,6 +260,98 @@ static struct nf_hook_ops ip_conntrack_local_in_ops = { .priority = NF_IP_PRI_LAST-1, }; +/* Sysctl support */ + +#ifdef CONFIG_SYSCTL + +/* From ip_conntrack_core.c */ +extern int ip_conntrack_max; + +/* From ip_conntrack_proto_tcp.c */ +extern unsigned long ip_ct_tcp_timeout_syn_sent; +extern unsigned long ip_ct_tcp_timeout_syn_recv; +extern unsigned long ip_ct_tcp_timeout_established; +extern unsigned long ip_ct_tcp_timeout_fin_wait; +extern unsigned long ip_ct_tcp_timeout_close_wait; +extern unsigned long ip_ct_tcp_timeout_last_ack; +extern unsigned long ip_ct_tcp_timeout_time_wait; +extern unsigned long ip_ct_tcp_timeout_close; + +/* From ip_conntrack_proto_udp.c */ +extern unsigned long ip_ct_udp_timeout; +extern unsigned long ip_ct_udp_timeout_stream; + +/* From ip_conntrack_proto_icmp.c */ +extern unsigned long ip_ct_icmp_timeout; + +/* From ip_conntrack_proto_icmp.c */ +extern unsigned long ip_ct_generic_timeout; + +static struct ctl_table_header *ip_ct_sysctl_header; + +static ctl_table ip_ct_sysctl_table[] = { + {NET_IPV4_NF_CONNTRACK_MAX, "ip_conntrack_max", + &ip_conntrack_max, sizeof(int), 0644, NULL, + &proc_dointvec}, + {NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_SYN_SENT, "ip_conntrack_tcp_timeout_syn_sent", + &ip_ct_tcp_timeout_syn_sent, sizeof(unsigned int), 0644, NULL, + &proc_dointvec_jiffies}, + {NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_SYN_RECV, "ip_conntrack_tcp_timeout_syn_recv", + &ip_ct_tcp_timeout_syn_recv, sizeof(unsigned int), 0644, NULL, + &proc_dointvec_jiffies}, + {NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_ESTABLISHED, "ip_conntrack_tcp_timeout_established", + &ip_ct_tcp_timeout_established, sizeof(unsigned int), 0644, NULL, + &proc_dointvec_jiffies}, + {NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_FIN_WAIT, "ip_conntrack_tcp_timeout_fin_wait", + &ip_ct_tcp_timeout_fin_wait, sizeof(unsigned int), 0644, NULL, + &proc_dointvec_jiffies}, + {NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_CLOSE_WAIT, "ip_conntrack_tcp_timeout_close_wait", + &ip_ct_tcp_timeout_close_wait, sizeof(unsigned int), 0644, NULL, + &proc_dointvec_jiffies}, + {NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_LAST_ACK, "ip_conntrack_tcp_timeout_last_ack", + &ip_ct_tcp_timeout_last_ack, sizeof(unsigned int), 0644, NULL, + &proc_dointvec_jiffies}, + {NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_TIME_WAIT, "ip_conntrack_tcp_timeout_time_wait", + &ip_ct_tcp_timeout_time_wait, sizeof(unsigned int), 0644, NULL, + &proc_dointvec_jiffies}, + {NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_CLOSE, "ip_conntrack_tcp_timeout_close", + &ip_ct_tcp_timeout_close, sizeof(unsigned int), 0644, NULL, + &proc_dointvec_jiffies}, + {NET_IPV4_NF_CONNTRACK_UDP_TIMEOUT, "ip_conntrack_udp_timeout", + &ip_ct_udp_timeout, sizeof(unsigned int), 0644, NULL, + &proc_dointvec_jiffies}, + {NET_IPV4_NF_CONNTRACK_UDP_TIMEOUT_STREAM, "ip_conntrack_udp_timeout_stream", + &ip_ct_udp_timeout_stream, sizeof(unsigned int), 0644, NULL, + &proc_dointvec_jiffies}, + {NET_IPV4_NF_CONNTRACK_ICMP_TIMEOUT, "ip_conntrack_icmp_timeout", + &ip_ct_icmp_timeout, sizeof(unsigned int), 0644, NULL, + &proc_dointvec_jiffies}, + {NET_IPV4_NF_CONNTRACK_GENERIC_TIMEOUT, "ip_conntrack_generic_timeout", + &ip_ct_generic_timeout, sizeof(unsigned int), 0644, NULL, + &proc_dointvec_jiffies}, + {0} +}; + +#define NET_IP_CONNTRACK_MAX 2089 + +static ctl_table ip_ct_netfilter_table[] = { + {NET_IPV4_NETFILTER, "netfilter", NULL, 0, 0555, ip_ct_sysctl_table, 0, 0, 0, 0, 0}, + {NET_IP_CONNTRACK_MAX, "ip_conntrack_max", + &ip_conntrack_max, sizeof(int), 0644, NULL, + &proc_dointvec}, + {0} +}; + +static ctl_table ip_ct_ipv4_table[] = { + {NET_IPV4, "ipv4", NULL, 0, 0555, ip_ct_netfilter_table, 0, 0, 0, 0, 0}, + {0} +}; + +static ctl_table ip_ct_net_table[] = { + {CTL_NET, "net", NULL, 0, 0555, ip_ct_ipv4_table, 0, 0, 0, 0, 0}, + {0} +}; +#endif static int init_or_cleanup(int init) { struct proc_dir_entry *proc; @@ -291,10 +387,20 @@ static int init_or_cleanup(int init) printk("ip_conntrack: can't register local in hook.\n"); goto cleanup_inoutandlocalops; } +#ifdef CONFIG_SYSCTL + ip_ct_sysctl_header = register_sysctl_table(ip_ct_net_table, 0); + if (ip_ct_sysctl_header == NULL) { + printk("ip_conntrack: can't register to sysctl.\n"); + goto cleanup; + } +#endif return ret; cleanup: +#ifdef CONFIG_SYSCTL + unregister_sysctl_table(ip_ct_sysctl_header); +#endif nf_unregister_hook(&ip_conntrack_local_in_ops); cleanup_inoutandlocalops: nf_unregister_hook(&ip_conntrack_out_ops); -- 2.53.0