BB: netfilter: support /proc conntrack flushing of specific ip addresses
authorJo-Philipp Wich <jow@openwrt.org>
Sun, 10 Aug 2014 09:21:19 +0000 (09:21 +0000)
committerJo-Philipp Wich <jow@openwrt.org>
Sun, 10 Aug 2014 09:21:19 +0000 (09:21 +0000)
Signed-off-by: Jo-Philipp Wich <jow@openwrt.org>
Backport of r42092

SVN-Revision: 42094

target/linux/generic/patches-3.10/604-netfilter_conntrack_flush.patch

index ecd46b6a2b04405206ec884fb3260187e31934ad..1b5e2abbec9f4b01bb415f987a7022b86c83f258 100644 (file)
@@ -1,12 +1,35 @@
 --- a/net/netfilter/nf_conntrack_standalone.c
 +++ b/net/netfilter/nf_conntrack_standalone.c
-@@ -268,10 +268,34 @@ static int ct_open(struct inode *inode,
+@@ -17,6 +17,7 @@
+ #include <linux/percpu.h>
+ #include <linux/netdevice.h>
+ #include <linux/security.h>
++#include <linux/inet.h>
+ #include <net/net_namespace.h>
+ #ifdef CONFIG_SYSCTL
+ #include <linux/sysctl.h>
+@@ -268,10 +269,63 @@ static int ct_open(struct inode *inode,
                        sizeof(struct ct_iter_state));
  }
  
-+static int kill_all(struct nf_conn *i, void *data)
++struct kill_request {
++      u16 family;
++      union nf_inet_addr addr;
++};
++
++static int kill_matching(struct nf_conn *i, void *data)
 +{
-+    return 1;
++      struct kill_request *kr = data;
++      struct nf_conntrack_tuple *t = &i->tuplehash[IP_CT_DIR_ORIGINAL].tuple;
++
++      if (!kr->family)
++              return 1;
++
++      if (t->src.l3num != kr->family)
++              return 0;
++
++      return (nf_inet_addr_cmp(&kr->addr, &t->src.u3) ||
++              nf_inet_addr_cmp(&kr->addr, &t->dst.u3));
 +}
 +
 +static ssize_t ct_file_write(struct file *file, const char __user *buf,
 +{
 +      struct seq_file *seq = file->private_data;
 +      struct net *net = seq_file_net(seq);
++      struct kill_request kr = { };
++      char req[INET6_ADDRSTRLEN] = { };
 +
-+      if (count) {
-+              char c;
++      if (count == 0)
++              return 0;
 +
-+              if (get_user(c, buf))
-+                      return -EFAULT;
++      if (count >= INET6_ADDRSTRLEN)
++              count = INET6_ADDRSTRLEN - 1;
 +
-+              if (c == 'f')
-+                      nf_ct_iterate_cleanup(net, kill_all, NULL);
++      if (copy_from_user(req, buf, count))
++              return -EFAULT;
++
++      if (strnchr(req, count, ':')) {
++              kr.family = AF_INET6;
++              if (!in6_pton(req, count, (void *)&kr.addr, '\n', NULL))
++                      return -EINVAL;
++      } else if (strnchr(req, count, '.')) {
++              kr.family = AF_INET;
++              if (!in4_pton(req, count, (void *)&kr.addr, '\n', NULL))
++                      return -EINVAL;
 +      }
++
++      nf_ct_iterate_cleanup(net, kill_matching, &kr);
++
 +      return count;
 +}
 +
@@ -35,7 +72,7 @@
        .llseek  = seq_lseek,
        .release = seq_release_net,
  };
-@@ -373,7 +397,7 @@ static int nf_conntrack_standalone_init_
+@@ -373,7 +427,7 @@ static int nf_conntrack_standalone_init_
  {
        struct proc_dir_entry *pde;