diff --git a/include/net/netfilter/nf_conntrack.h b/include/net/netfilter/nf_conntrack.h index 90690e37a56f..159bc1934679 100644 --- a/include/net/netfilter/nf_conntrack.h +++ b/include/net/netfilter/nf_conntrack.h @@ -55,6 +55,11 @@ struct nf_conntrack_net { #include #include +/* Handle NATTYPE Stuff,only if NATTYPE module was defined */ +#ifdef CONFIG_IP_NF_TARGET_NATTYPE_MODULE +#include +#endif + struct nf_conn { /* Usage count in here is 1 for hash table, 1 per skb, * plus 1 for any connection(s) we are `master' for @@ -103,6 +108,10 @@ struct nf_conn { /* Extensions */ struct nf_ct_ext *ext; +#ifdef CONFIG_IP_NF_TARGET_NATTYPE_MODULE + unsigned long nattype_entry; +#endif + /* Storage reserved for other modules, must be the last member */ union nf_conntrack_proto proto; }; diff --git a/include/net/netfilter/nf_conntrack_core.h b/include/net/netfilter/nf_conntrack_core.h index 09f2efea0b97..a6d34aa9abea 100644 --- a/include/net/netfilter/nf_conntrack_core.h +++ b/include/net/netfilter/nf_conntrack_core.h @@ -43,6 +43,7 @@ void nf_conntrack_cleanup_end(void); bool nf_ct_invert_tuple(struct nf_conntrack_tuple *inverse, const struct nf_conntrack_tuple *orig); +extern bool (*nattype_refresh_timer)(unsigned long nattype) __rcu __read_mostly; /* Find a connection corresponding to a tuple. */ struct nf_conntrack_tuple_hash * diff --git a/net/ipv4/netfilter/ipt_NATTYPE.c b/net/ipv4/netfilter/ipt_NATTYPE.c index 32c23204ff61..ca184d1e8909 100644 --- a/net/ipv4/netfilter/ipt_NATTYPE.c +++ b/net/ipv4/netfilter/ipt_NATTYPE.c @@ -32,6 +32,7 @@ static const char * const modes[] = {"MODE_DNAT", "MODE_FORWARD_IN", struct ipt_nattype { struct list_head list; struct timer_list timeout; + unsigned char is_valid; unsigned short proto; /* Protocol: TCP or UDP */ struct nf_nat_ipv4_range range; /* LAN side src info*/ unsigned short nat_port; /* Routed NAT port */ @@ -67,13 +68,24 @@ static void nattype_free(struct ipt_nattype *nte) /* netfilter NATTYPE nattype_refresh_timer() * Refresh the timer for this object. */ -static bool nattype_refresh_timer(struct ipt_nattype *nte) +bool nattype_refresh_timer_impl(unsigned long nat_type) { + struct ipt_nattype *nte = (struct ipt_nattype *)nat_type; + + if (!nte) + return false; + spin_lock_bh(&nattype_lock); + if (!nte->is_valid) { + spin_unlock_bh(&nattype_lock); + return false; + } if (del_timer(&nte->timeout)) { nte->timeout.expires = jiffies + NATTYPE_TIMEOUT * HZ; add_timer(&nte->timeout); + spin_unlock_bh(&nattype_lock); return true; } + spin_unlock_bh(&nattype_lock); return false; } @@ -92,6 +104,7 @@ static void nattype_timer_timeout(unsigned long in_nattype) nattype_nte_debug_print(nte, "timeout"); spin_lock_bh(&nattype_lock); list_del(&nte->list); + memset(nte, 0, sizeof(struct ipt_nattype)); spin_unlock_bh(&nattype_lock); nattype_free(nte); } @@ -267,7 +280,8 @@ static unsigned int nattype_nat(struct sk_buff *skb, * to include the reply as source */ DEBUGP("Expand ingress conntrack=%p, type=%d, src[%pI4:%d]\n", - ct, ctinfo, &newrange.min_ip, ntohs(newrange.min.all)); + ct, ctinfo, &newrange.min_ip, ntohs(newrange.min.all)); + ct->nattype_entry = (unsigned long)nte; ret = nf_nat_setup_info(ct, &newrange, NF_NAT_MANIP_DST); DEBUGP("Expand returned: %d\n", ret); return ret; @@ -307,12 +321,13 @@ static unsigned int nattype_forward(struct sk_buff *skb, if (!nattype_packet_in_match(nte, skb, info)) continue; + spin_unlock_bh(&nattype_lock); /* netfilter NATTYPE * Refresh the timer, if we fail, break * out and forward fail as though we never * found the entry. */ - if (!nattype_refresh_timer(nte)) + if (!nattype_refresh_timer((unsigned long)nte)) break; /* netfilter NATTYPE @@ -320,7 +335,6 @@ static unsigned int nattype_forward(struct sk_buff *skb, * entry values should not change so print * them outside the lock. */ - spin_unlock_bh(&nattype_lock); nattype_nte_debug_print(nte, "refresh"); DEBUGP("FORWARD_IN_ACCEPT\n"); return NF_ACCEPT; @@ -386,13 +400,13 @@ static unsigned int nattype_forward(struct sk_buff *skb, list_for_each_entry(nte2, &nattype_list, list) { if (!nattype_compare(nte, nte2)) continue; - + spin_unlock_bh(&nattype_lock); /* netfilter NATTYPE * If we can not refresh this entry, insert our new * entry as this one is timed out and will be removed * from the list shortly. */ - if (!nattype_refresh_timer(nte2)) + if (!nattype_refresh_timer((unsigned long)nte2)) break; /* netfilter NATTYPE @@ -401,7 +415,6 @@ static unsigned int nattype_forward(struct sk_buff *skb, * * Free up the new entry. */ - spin_unlock_bh(&nattype_lock); nattype_nte_debug_print(nte2, "refresh"); nattype_free(nte); return XT_CONTINUE; @@ -413,6 +426,8 @@ static unsigned int nattype_forward(struct sk_buff *skb, nte->timeout.expires = jiffies + (NATTYPE_TIMEOUT * HZ); add_timer(&nte->timeout); list_add(&nte->list, &nattype_list); + ct->nattype_entry = (unsigned long)nte; + nte->is_valid = 1; spin_unlock_bh(&nattype_lock); nattype_nte_debug_print(nte, "ADD"); return XT_CONTINUE; @@ -545,6 +560,8 @@ static struct xt_target nattype = { static int __init init(void) { + WARN_ON(nattype_refresh_timer); + RCU_INIT_POINTER(nattype_refresh_timer, nattype_refresh_timer_impl); return xt_register_target(&nattype); } diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c index 200cdad3ff3a..6cd4c2e78bdc 100644 --- a/net/netfilter/nf_conntrack_core.c +++ b/net/netfilter/nf_conntrack_core.c @@ -64,6 +64,9 @@ EXPORT_SYMBOL_GPL(nf_conntrack_expect_lock); struct hlist_nulls_head *nf_conntrack_hash __read_mostly; EXPORT_SYMBOL_GPL(nf_conntrack_hash); +bool (*nattype_refresh_timer)(unsigned long nattype) __rcu __read_mostly; +EXPORT_SYMBOL(nattype_refresh_timer); + struct conntrack_gc_work { struct delayed_work dwork; u32 last_bucket; @@ -1495,6 +1498,10 @@ init_conntrack(struct net *net, struct nf_conn *tmpl, #endif #ifdef CONFIG_NF_CONNTRACK_SECMARK ct->secmark = exp->master->secmark; +#endif +/* Initialize the NAT type entry. */ +#if defined(CONFIG_IP_NF_TARGET_NATTYPE_MODULE) + ct->nattype_entry = 0; #endif NF_CT_STAT_INC(net, expect_new); } @@ -1784,6 +1791,10 @@ void __nf_ct_refresh_acct(struct nf_conn *ct, u32 extra_jiffies, bool do_acct) { +#if defined(CONFIG_IP_NF_TARGET_NATTYPE_MODULE) + bool (*nattype_ref_timer)(unsigned long nattype); +#endif + /* Only update if this is not a fixed timeout */ if (test_bit(IPS_FIXED_TIMEOUT_BIT, &ct->status)) goto acct; @@ -1794,6 +1805,14 @@ void __nf_ct_refresh_acct(struct nf_conn *ct, if (READ_ONCE(ct->timeout) != extra_jiffies) WRITE_ONCE(ct->timeout, extra_jiffies); + +/* Refresh the NAT type entry. */ +#if defined(CONFIG_IP_NF_TARGET_NATTYPE_MODULE) + nattype_ref_timer = rcu_dereference(nattype_refresh_timer); + if (nattype_ref_timer) + nattype_ref_timer(ct->nattype_entry); +#endif + acct: if (do_acct) nf_ct_acct_update(ct, ctinfo, skb->len);