diff --git a/include/linux/netfilter/nfnetlink_conntrack.h b/include/linux/netfilter/nfnetlink_conntrack.h index 668ec94..0a300df 100644 --- a/include/linux/netfilter/nfnetlink_conntrack.h +++ b/include/linux/netfilter/nfnetlink_conntrack.h @@ -29,6 +29,9 @@ enum ctattr_type { CTA_HELP, CTA_NAT, CTA_TIMEOUT, +#if defined(CONFIG_IP_NF_CT_FIXED_TIMEOUT) || defined(CONFIG_NF_CT_FIXED_TIMEOUT) + CTA_FIXED_TIMEOUT, +#endif CTA_MARK, CTA_COUNTERS_ORIG, CTA_COUNTERS_REPLY, diff --git a/include/linux/netfilter_ipv4/ip_conntrack.h b/include/linux/netfilter_ipv4/ip_conntrack.h index d54d7b2..6093ed5 100644 --- a/include/linux/netfilter_ipv4/ip_conntrack.h +++ b/include/linux/netfilter_ipv4/ip_conntrack.h @@ -85,6 +85,11 @@ struct ip_conntrack /* Timer function; drops refcnt when it goes off. */ struct timer_list timeout; +#ifdef CONFIG_IP_NF_CT_FIXED_TIMEOUT + /* Is timeout fixed ? */ + struct timer_list fixed_timeout; +#endif + #ifdef CONFIG_IP_NF_CT_ACCT /* Accounting Information (same cache line as other written members) */ struct ip_conntrack_counter counters[IP_CT_DIR_MAX]; diff --git a/include/net/netfilter/nf_conntrack.h b/include/net/netfilter/nf_conntrack.h index 916013c..7c0b46d 100644 --- a/include/net/netfilter/nf_conntrack.h +++ b/include/net/netfilter/nf_conntrack.h @@ -99,6 +99,12 @@ struct nf_conn /* Timer function; drops refcnt when it goes off. */ struct timer_list timeout; +#ifdef CONFIG_NF_CT_FIXED_TIMEOUT + /* Is timeout fixed ? */ + struct timer_list fixed_timeout; +#endif + + #ifdef CONFIG_NF_CT_ACCT /* Accounting Information (same cache line as other written members) */ struct ip_conntrack_counter counters[IP_CT_DIR_MAX]; diff --git a/net/ipv4/netfilter/Kconfig b/net/ipv4/netfilter/Kconfig index 882b842..6cae515 100644 --- a/net/ipv4/netfilter/Kconfig +++ b/net/ipv4/netfilter/Kconfig @@ -46,6 +46,18 @@ config IP_NF_CT_ACCT If unsure, say `N'. +config IP_NF_CT_FIXED_TIMEOUT + bool "Connection tracking fixed timeout (EXPERIMENTAL)" + depends on EXPERIMENTAL && IP_NF_CONNTRACK + help + If this option is enabled, the connection tracking code will + be able to have connection that will expire automatically after + a given time. + + This feature can be used with libnetfilter_conntrack library. + + If unsure, say `N'. + config IP_NF_CONNTRACK_MARK bool 'Connection mark tracking support' depends on IP_NF_CONNTRACK diff --git a/net/ipv4/netfilter/ip_conntrack_core.c b/net/ipv4/netfilter/ip_conntrack_core.c index ceaabc1..17ebe9b 100644 --- a/net/ipv4/netfilter/ip_conntrack_core.c +++ b/net/ipv4/netfilter/ip_conntrack_core.c @@ -319,6 +319,11 @@ destroy_conntrack(struct nf_conntrack *n IP_NF_ASSERT(atomic_read(&nfct->use) == 0); IP_NF_ASSERT(!timer_pending(&ct->timeout)); +#ifdef CONFIG_IP_NF_CT_FIXED_TIMEOUT + if (timer_pending(&ct->fixed_timeout)) { + del_timer(&ct->fixed_timeout); + } +#endif ip_conntrack_event(IPCT_DESTROY, ct); set_bit(IPS_DYING_BIT, &ct->status); @@ -359,6 +364,15 @@ static void death_by_timeout(unsigned lo { struct ip_conntrack *ct = (void *)ul_conntrack; +#ifdef CONFIG_IP_NF_CT_FIXED_TIMEOUT + /* delete the timer which has not timeout */ + if (timer_pending(&ct->timeout)) { + del_timer(&ct->timeout); + } + if (timer_pending(&ct->fixed_timeout)) { + del_timer(&ct->fixed_timeout); + } +#endif write_lock_bh(&ip_conntrack_lock); /* Inside lock so preempt is disabled on module removal path. * Otherwise we can get spurious warnings. */ @@ -670,6 +684,12 @@ struct ip_conntrack *ip_conntrack_alloc( conntrack->timeout.data = (unsigned long)conntrack; conntrack->timeout.function = death_by_timeout; +#ifdef CONFIG_IP_NF_CT_FIXED_TIMEOUT + init_timer(&conntrack->fixed_timeout); + conntrack->fixed_timeout.data = (unsigned long)conntrack; + conntrack->fixed_timeout.function = death_by_timeout; +#endif + atomic_inc(&ip_conntrack_count); return conntrack; @@ -724,6 +744,7 @@ init_conntrack(struct ip_conntrack_tuple /* this is ugly, but there is no other place where to put it */ conntrack->nat.masq_index = exp->master->nat.masq_index; #endif + nf_conntrack_get(&conntrack->master->ct_general); CONNTRACK_STAT_INC(expect_new); } else { @@ -1135,12 +1156,12 @@ void __ip_ct_refresh_acct(struct ip_conn ct->timeout.expires = extra_jiffies; event = IPCT_REFRESH; } else { - /* Need del_timer for race avoidance (may already be dying). */ - if (del_timer(&ct->timeout)) { - ct->timeout.expires = jiffies + extra_jiffies; - add_timer(&ct->timeout); - event = IPCT_REFRESH; - } + /* Need del_timer for race avoidance (may already be dying). */ + if (del_timer(&ct->timeout)) { + ct->timeout.expires = jiffies + extra_jiffies; + add_timer(&ct->timeout); + event = IPCT_REFRESH; + } } #ifdef CONFIG_IP_NF_CT_ACCT diff --git a/net/ipv4/netfilter/ip_conntrack_netlink.c b/net/ipv4/netfilter/ip_conntrack_netlink.c index 9b6e19b..30a32f0 100644 --- a/net/ipv4/netfilter/ip_conntrack_netlink.c +++ b/net/ipv4/netfilter/ip_conntrack_netlink.c @@ -42,7 +42,7 @@ MODULE_LICENSE("GPL"); -static char __initdata version[] = "0.90"; +static char __initdata version[] = "0.91"; #if 0 #define DEBUGP printk @@ -953,6 +953,26 @@ ctnetlink_change_timeout(struct ip_connt return 0; } + +#ifdef CONFIG_IP_NF_CT_FIXED_TIMEOUT +static inline int +ctnetlink_change_fixed_timeout(struct ip_conntrack *ct, struct nfattr *cda[]) +{ + u_int32_t timeout = ntohl(*(u_int32_t *)NFA_DATA(cda[CTA_FIXED_TIMEOUT-1])); + + /* test if timer has already been set */ + if (timer_pending(&ct->fixed_timeout)){ + if (!del_timer(&ct->fixed_timeout)) + return -ETIME; + } + + ct->fixed_timeout.expires = jiffies + timeout * HZ; + add_timer(&ct->fixed_timeout); + + return 0; +} +#endif /* CONFIG_IP_NF_CT_FIXED_TIMEOUT */ + static inline int ctnetlink_change_protoinfo(struct ip_conntrack *ct, struct nfattr *cda[]) { @@ -991,6 +1011,14 @@ ctnetlink_change_conntrack(struct ip_con return err; } +#ifdef CONFIG_IP_NF_CT_FIXED_TIMEOUT + if (cda[CTA_FIXED_TIMEOUT-1]) { + err = ctnetlink_change_fixed_timeout(ct, cda); + if (err < 0) + return err; + } +#endif + if (cda[CTA_STATUS-1]) { err = ctnetlink_change_status(ct, cda); if (err < 0) @@ -1030,7 +1058,15 @@ ctnetlink_create_conntrack(struct nfattr goto err; ct->timeout.expires = ntohl(*(u_int32_t *)NFA_DATA(cda[CTA_TIMEOUT-1])); + /* we admit jiffies delay on timeout even if is fixed */ ct->timeout.expires = jiffies + ct->timeout.expires * HZ; + +#ifdef CONFIG_IP_NF_CT_FIXED_TIMEOUT + if (cda[CTA_FIXED_TIMEOUT-1]) { + ct->fixed_timeout.expires = ntohl(*(u_int32_t *)NFA_DATA(cda[CTA_FIXED_TIMEOUT-1])); + } +#endif + ct->status |= IPS_CONFIRMED; err = ctnetlink_change_status(ct, cda); @@ -1051,6 +1087,13 @@ ctnetlink_create_conntrack(struct nfattr ct->helper = ip_conntrack_helper_find_get(rtuple); add_timer(&ct->timeout); + +#ifdef CONFIG_IP_NF_CT_FIXED_TIMEOUT + if (cda[CTA_FIXED_TIMEOUT-1]) { + add_timer(&ct->fixed_timeout); + } +#endif + ip_conntrack_hash_insert(ct); if (ct->helper) diff --git a/net/netfilter/Kconfig b/net/netfilter/Kconfig index 332acb3..e44158f 100644 --- a/net/netfilter/Kconfig +++ b/net/netfilter/Kconfig @@ -60,6 +60,18 @@ config NF_CONNTRACK_MARK of packets, but this mark value is kept in the conntrack session instead of the individual packets. +config CONFIG_NF_CT_FIXED_TIMEOUT + bool "Connection with fixed expiration delay (EXPERIMENTAL)" + depends on EXPERIMENTAL && NF_CONNTRACK + help + If this option is enabled, the connection tracking code will + be able to have connection that will expire automatically after + a given time. + + This feature can be used with libnetfilter_conntrack library. + + If unsure, say `N'. + config NF_CONNTRACK_EVENTS bool "Connection tracking events (EXPERIMENTAL)" depends on EXPERIMENTAL && NF_CONNTRACK diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c index 56389c8..7b0f2e8 100644 --- a/net/netfilter/nf_conntrack_core.c +++ b/net/netfilter/nf_conntrack_core.c @@ -572,6 +572,12 @@ destroy_conntrack(struct nf_conntrack *n NF_CT_ASSERT(atomic_read(&nfct->use) == 0); NF_CT_ASSERT(!timer_pending(&ct->timeout)); +#ifdef CONFIG_NF_CT_FIXED_TIMEOUT + if (timer_pending(&ct->fixed_timeout)) { + del_timer(&ct->fixed_timeout); + } +#endif + nf_conntrack_event(IPCT_DESTROY, ct); set_bit(IPS_DYING_BIT, &ct->status); @@ -616,6 +622,16 @@ static void death_by_timeout(unsigned lo { struct nf_conn *ct = (void *)ul_conntrack; +#ifdef CONFIG_NF_CT_FIXED_TIMEOUT + /* delete the timer which has not timeout */ + if (timer_pending(&ct->timeout)) { + del_timer(&ct->timeout); + } + if (timer_pending(&ct->fixed_timeout)) { + del_timer(&ct->fixed_timeout); + } +#endif + write_lock_bh(&nf_conntrack_lock); /* Inside lock so preempt is disabled on module removal path. * Otherwise we can get spurious warnings. */ @@ -930,6 +946,13 @@ __nf_conntrack_alloc(const struct nf_con conntrack->timeout.data = (unsigned long)conntrack; conntrack->timeout.function = death_by_timeout; +#ifdef CONFIG_NF_CT_FIXED_TIMEOUT + init_timer(&conntrack->fixed_timeout); + conntrack->fixed_timeout.data = (unsigned long)conntrack; + conntrack->fixed_timeout.function = death_by_timeout; +#endif + + atomic_inc(&nf_conntrack_count); out: read_unlock_bh(&nf_ct_cache_lock); diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c index 0e0e9d7..811560b 100644 --- a/net/netfilter/nf_conntrack_netlink.c +++ b/net/netfilter/nf_conntrack_netlink.c @@ -971,6 +971,26 @@ ctnetlink_change_timeout(struct nf_conn return 0; } +#ifdef CONFIG_NF_CT_FIXED_TIMEOUT +static inline int +ctnetlink_change_fixed_timeout(struct ip_conntrack *ct, struct nfattr *cda[]) +{ + u_int32_t timeout = ntohl(*(u_int32_t *)NFA_DATA(cda[CTA_FIXED_TIMEOUT-1])); + + /* test if timer has already been set */ + if (timer_pending(&ct->fixed_timeout)){ + if (!del_timer(&ct->fixed_timeout)) + return -ETIME; + } + + ct->fixed_timeout.expires = jiffies + timeout * HZ; + add_timer(&ct->fixed_timeout); + + return 0; +} +#endif /* CONFIG_NF_CT_FIXED_TIMEOUT */ + + static inline int ctnetlink_change_protoinfo(struct nf_conn *ct, struct nfattr *cda[]) { @@ -1010,6 +1030,15 @@ ctnetlink_change_conntrack(struct nf_con return err; } + +#ifdef CONFIG_NF_CT_FIXED_TIMEOUT + if (cda[CTA_FIXED_TIMEOUT-1]) { + err = ctnetlink_change_fixed_timeout(ct, cda); + if (err < 0) + return err; + } +#endif + if (cda[CTA_STATUS-1]) { err = ctnetlink_change_status(ct, cda); if (err < 0) @@ -1049,6 +1078,12 @@ ctnetlink_create_conntrack(struct nfattr goto err; ct->timeout.expires = ntohl(*(u_int32_t *)NFA_DATA(cda[CTA_TIMEOUT-1])); +#ifdef CONFIG_NF_CT_FIXED_TIMEOUT + if (cda[CTA_FIXED_TIMEOUT-1]) { + ct->fixed_timeout.expires = ntohl(*(u_int32_t *)NFA_DATA(cda[CTA_FIXED_TIMEOUT-1])); + } +#endif + ct->timeout.expires = jiffies + ct->timeout.expires * HZ; ct->status |= IPS_CONFIRMED; @@ -1068,6 +1103,13 @@ ctnetlink_create_conntrack(struct nfattr #endif add_timer(&ct->timeout); + +#ifdef CONFIG_NF_CT_FIXED_TIMEOUT + if (cda[CTA_FIXED_TIMEOUT-1]) { + add_timer(&ct->fixed_timeout); + } +#endif + nf_conntrack_hash_insert(ct); DEBUGP("conntrack with id %u inserted\n", ct->id);