/* Metin KAYA */ Clearing IP Connection Tracks: The WAN connections are cached by netfilter for a while. On the other hand, this cause LAN clients attempt to use the remote IP addresses although they are not up interfaces by now. Thus, the netfilter cache must be flushed after a remote network interface becomes down. Index: net/ipv4/netfilter/nf_conntrack_l3proto_ipv4_compat.c =================================================================== --- net/ipv4/netfilter/nf_conntrack_l3proto_ipv4_compat.c +++ net/ipv4/netfilter/nf_conntrack_l3proto_ipv4_compat.c @@ -18,6 +18,10 @@ #include #include +#include + #if 0 #define DEBUGP printk #else @@ -41,6 +45,66 @@ unsigned int bucket; }; +static struct proc_dir_entry *proc_entry = NULL; +static u_int32_t dst_ip_to_be_cleared = 0; +rwlock_t nf_clear_conntrack_lock; + +static int clear_nf_conntracks(struct file *file, const char __user *input, unsigned long size, void *data) +{ + unsigned int i; + char buffer[20]; + struct list_head *e; + struct nf_conntrack_tuple_hash *hash; + struct nf_conn *conntrack; + int len = 0; + + if (*input) { + if (size > 20) + len = 20; + else + len = size; + + if (copy_from_user(buffer, input, len)) + return -EFAULT; + + if (len < 20) + buffer[len] = '\0'; + + for (i = 0; i < len; i++) { + if (buffer[i] == '\n') { + buffer[i] = '\0'; + len = i; + break; + } + } + + dst_ip_to_be_cleared = in_aton(buffer); + } + + read_lock_bh(&nf_clear_conntrack_lock); + for (i = 0; i < nf_conntrack_htable_size; i++) { + list_for_each(e, &nf_conntrack_hash[i]) { + hash = (struct nf_conntrack_tuple_hash *) e; + conntrack = nf_ct_tuplehash_to_ctrack(hash); + + if (dst_ip_to_be_cleared == conntrack->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u3.ip) { + write_lock_bh(&nf_clear_conntrack_lock); + if (del_timer(&(conntrack->timeout))) { + conntrack->timeout.expires = jiffies; + add_timer(&(conntrack->timeout)); + printk("IP ConnTrack: clearing %u.%u.%u.%u\n", NIPQUAD(conntrack->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u3.ip)); + } + write_unlock_bh(&nf_clear_conntrack_lock); + } + } + } + read_unlock_bh(&nf_clear_conntrack_lock); + + return size; +} + static struct list_head *ct_get_first(struct seq_file *seq) { struct ct_iter_state *st = seq->private; @@ -391,11 +455,23 @@ if (!proc_stat) goto err3; + proc_entry = create_proc_entry( "ip_clear_ipconntrack", 0644, proc_net); + if (proc_entry == NULL) { + printk("Unable to create /proc/net/ip_clear_ipconntrack!\n"); + goto err4; + } else { + proc_entry->write_proc = clear_nf_conntracks; + proc_entry->owner = THIS_MODULE; + } + proc_stat->proc_fops = &ct_cpu_seq_fops; proc_stat->owner = THIS_MODULE; return 0; - +err4: + proc_net_remove("ip_clear_ipconntrack"); err3: proc_net_remove("ip_conntrack_expect"); err2: @@ -409,4 +485,7 @@ remove_proc_entry("ip_conntrack", proc_net_stat); proc_net_remove("ip_conntrack_expect"); proc_net_remove("ip_conntrack"); + proc_net_remove("ip_clear_ipconntrack"); }