[PATCH 03/15] netfilter: factor out packet duplication for IPv4/IPv6

2015-08-20 Thread Pablo Neira Ayuso
Extracted from the xtables TEE target. This creates two new modules for IPv4
and IPv6 that are shared between the TEE target and the new nf_tables dup
expressions.

Signed-off-by: Pablo Neira Ayuso pa...@netfilter.org
---
 include/net/netfilter/ipv4/nf_dup_ipv4.h |7 ++
 include/net/netfilter/ipv6/nf_dup_ipv6.h |7 ++
 net/ipv4/netfilter/Kconfig   |6 ++
 net/ipv4/netfilter/Makefile  |2 +
 net/ipv4/netfilter/nf_dup_ipv4.c |  120 +++
 net/ipv6/netfilter/Kconfig   |6 ++
 net/ipv6/netfilter/Makefile  |2 +
 net/ipv6/netfilter/nf_dup_ipv6.c |   96 ++
 net/netfilter/Kconfig|2 +
 net/netfilter/xt_TEE.c   |  158 ++
 10 files changed, 254 insertions(+), 152 deletions(-)
 create mode 100644 include/net/netfilter/ipv4/nf_dup_ipv4.h
 create mode 100644 include/net/netfilter/ipv6/nf_dup_ipv6.h
 create mode 100644 net/ipv4/netfilter/nf_dup_ipv4.c
 create mode 100644 net/ipv6/netfilter/nf_dup_ipv6.c

diff --git a/include/net/netfilter/ipv4/nf_dup_ipv4.h 
b/include/net/netfilter/ipv4/nf_dup_ipv4.h
new file mode 100644
index 000..42008f1
--- /dev/null
+++ b/include/net/netfilter/ipv4/nf_dup_ipv4.h
@@ -0,0 +1,7 @@
+#ifndef _NF_DUP_IPV4_H_
+#define _NF_DUP_IPV4_H_
+
+void nf_dup_ipv4(struct sk_buff *skb, unsigned int hooknum,
+const struct in_addr *gw, int oif);
+
+#endif /* _NF_DUP_IPV4_H_ */
diff --git a/include/net/netfilter/ipv6/nf_dup_ipv6.h 
b/include/net/netfilter/ipv6/nf_dup_ipv6.h
new file mode 100644
index 000..ed6bd66
--- /dev/null
+++ b/include/net/netfilter/ipv6/nf_dup_ipv6.h
@@ -0,0 +1,7 @@
+#ifndef _NF_DUP_IPV6_H_
+#define _NF_DUP_IPV6_H_
+
+void nf_dup_ipv6(struct sk_buff *skb, unsigned int hooknum,
+const struct in6_addr *gw, int oif);
+
+#endif /* _NF_DUP_IPV6_H_ */
diff --git a/net/ipv4/netfilter/Kconfig b/net/ipv4/netfilter/Kconfig
index 2199a5d..0142ea2 100644
--- a/net/ipv4/netfilter/Kconfig
+++ b/net/ipv4/netfilter/Kconfig
@@ -67,6 +67,12 @@ config NF_TABLES_ARP
 
 endif # NF_TABLES
 
+config NF_DUP_IPV4
+   tristate Netfilter IPv4 packet duplication to alternate destination
+   help
+ This option enables the nf_dup_ipv4 core, which duplicates an IPv4
+ packet to be rerouted to another destination.
+
 config NF_LOG_ARP
tristate ARP packet logging
default m if NETFILTER_ADVANCED=n
diff --git a/net/ipv4/netfilter/Makefile b/net/ipv4/netfilter/Makefile
index 7fe6c70..9136ffc 100644
--- a/net/ipv4/netfilter/Makefile
+++ b/net/ipv4/netfilter/Makefile
@@ -70,3 +70,5 @@ obj-$(CONFIG_IP_NF_ARP_MANGLE) += arpt_mangle.o
 
 # just filtering instance of ARP tables for now
 obj-$(CONFIG_IP_NF_ARPFILTER) += arptable_filter.o
+
+obj-$(CONFIG_NF_DUP_IPV4) += nf_dup_ipv4.o
diff --git a/net/ipv4/netfilter/nf_dup_ipv4.c b/net/ipv4/netfilter/nf_dup_ipv4.c
new file mode 100644
index 000..eff85ab
--- /dev/null
+++ b/net/ipv4/netfilter/nf_dup_ipv4.c
@@ -0,0 +1,120 @@
+/*
+ * (C) 2007 by Sebastian Cla??en sebastian.clas...@freenet.ag
+ * (C) 2007-2010 by Jan Engelhardt jeng...@medozas.de
+ *
+ * Extracted from xt_TEE.c
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 or later, as
+ * published by the Free Software Foundation.
+ */
+#include linux/ip.h
+#include linux/module.h
+#include linux/percpu.h
+#include linux/route.h
+#include linux/skbuff.h
+#include net/checksum.h
+#include net/icmp.h
+#include net/ip.h
+#include net/route.h
+#include net/netfilter/ipv4/nf_dup_ipv4.h
+#if IS_ENABLED(CONFIG_NF_CONNTRACK)
+#include net/netfilter/nf_conntrack.h
+#endif
+
+static struct net *pick_net(struct sk_buff *skb)
+{
+#ifdef CONFIG_NET_NS
+   const struct dst_entry *dst;
+
+   if (skb-dev != NULL)
+   return dev_net(skb-dev);
+   dst = skb_dst(skb);
+   if (dst != NULL  dst-dev != NULL)
+   return dev_net(dst-dev);
+#endif
+   return init_net;
+}
+
+static bool nf_dup_ipv4_route(struct sk_buff *skb, const struct in_addr *gw,
+ int oif)
+{
+   const struct iphdr *iph = ip_hdr(skb);
+   struct net *net = pick_net(skb);
+   struct rtable *rt;
+   struct flowi4 fl4;
+
+   memset(fl4, 0, sizeof(fl4));
+   if (oif != -1)
+   fl4.flowi4_oif = oif;
+
+   fl4.daddr = gw-s_addr;
+   fl4.flowi4_tos = RT_TOS(iph-tos);
+   fl4.flowi4_scope = RT_SCOPE_UNIVERSE;
+   fl4.flowi4_flags = FLOWI_FLAG_KNOWN_NH;
+   rt = ip_route_output_key(net, fl4);
+   if (IS_ERR(rt))
+   return false;
+
+   skb_dst_drop(skb);
+   skb_dst_set(skb, rt-dst);
+   skb-dev  = rt-dst.dev;
+   skb-protocol = htons(ETH_P_IP);
+
+   return true;
+}
+
+void nf_dup_ipv4(struct sk_buff *skb, unsigned int hooknum,
+const struct in_addr 

[PATCH 03/15] netfilter: factor out packet duplication for IPv4/IPv6

2015-08-19 Thread Pablo Neira Ayuso
Extracted from the xtables TEE target. This creates two new modules for IPv4
and IPv6 that are shared between the TEE target and the new nf_tables dup
expressions.

Signed-off-by: Pablo Neira Ayuso pa...@netfilter.org
---
 include/net/netfilter/ipv4/nf_dup_ipv4.h |7 ++
 include/net/netfilter/ipv6/nf_dup_ipv6.h |7 ++
 net/ipv4/netfilter/Kconfig   |6 ++
 net/ipv4/netfilter/Makefile  |2 +
 net/ipv4/netfilter/nf_dup_ipv4.c |  120 +++
 net/ipv6/netfilter/Kconfig   |6 ++
 net/ipv6/netfilter/Makefile  |2 +
 net/ipv6/netfilter/nf_dup_ipv6.c |   96 ++
 net/netfilter/Kconfig|2 +
 net/netfilter/xt_TEE.c   |  158 ++
 10 files changed, 254 insertions(+), 152 deletions(-)
 create mode 100644 include/net/netfilter/ipv4/nf_dup_ipv4.h
 create mode 100644 include/net/netfilter/ipv6/nf_dup_ipv6.h
 create mode 100644 net/ipv4/netfilter/nf_dup_ipv4.c
 create mode 100644 net/ipv6/netfilter/nf_dup_ipv6.c

diff --git a/include/net/netfilter/ipv4/nf_dup_ipv4.h 
b/include/net/netfilter/ipv4/nf_dup_ipv4.h
new file mode 100644
index 000..42008f1
--- /dev/null
+++ b/include/net/netfilter/ipv4/nf_dup_ipv4.h
@@ -0,0 +1,7 @@
+#ifndef _NF_DUP_IPV4_H_
+#define _NF_DUP_IPV4_H_
+
+void nf_dup_ipv4(struct sk_buff *skb, unsigned int hooknum,
+const struct in_addr *gw, int oif);
+
+#endif /* _NF_DUP_IPV4_H_ */
diff --git a/include/net/netfilter/ipv6/nf_dup_ipv6.h 
b/include/net/netfilter/ipv6/nf_dup_ipv6.h
new file mode 100644
index 000..ed6bd66
--- /dev/null
+++ b/include/net/netfilter/ipv6/nf_dup_ipv6.h
@@ -0,0 +1,7 @@
+#ifndef _NF_DUP_IPV6_H_
+#define _NF_DUP_IPV6_H_
+
+void nf_dup_ipv6(struct sk_buff *skb, unsigned int hooknum,
+const struct in6_addr *gw, int oif);
+
+#endif /* _NF_DUP_IPV6_H_ */
diff --git a/net/ipv4/netfilter/Kconfig b/net/ipv4/netfilter/Kconfig
index 2199a5d..0142ea2 100644
--- a/net/ipv4/netfilter/Kconfig
+++ b/net/ipv4/netfilter/Kconfig
@@ -67,6 +67,12 @@ config NF_TABLES_ARP
 
 endif # NF_TABLES
 
+config NF_DUP_IPV4
+   tristate Netfilter IPv4 packet duplication to alternate destination
+   help
+ This option enables the nf_dup_ipv4 core, which duplicates an IPv4
+ packet to be rerouted to another destination.
+
 config NF_LOG_ARP
tristate ARP packet logging
default m if NETFILTER_ADVANCED=n
diff --git a/net/ipv4/netfilter/Makefile b/net/ipv4/netfilter/Makefile
index 7fe6c70..9136ffc 100644
--- a/net/ipv4/netfilter/Makefile
+++ b/net/ipv4/netfilter/Makefile
@@ -70,3 +70,5 @@ obj-$(CONFIG_IP_NF_ARP_MANGLE) += arpt_mangle.o
 
 # just filtering instance of ARP tables for now
 obj-$(CONFIG_IP_NF_ARPFILTER) += arptable_filter.o
+
+obj-$(CONFIG_NF_DUP_IPV4) += nf_dup_ipv4.o
diff --git a/net/ipv4/netfilter/nf_dup_ipv4.c b/net/ipv4/netfilter/nf_dup_ipv4.c
new file mode 100644
index 000..eff85ab
--- /dev/null
+++ b/net/ipv4/netfilter/nf_dup_ipv4.c
@@ -0,0 +1,120 @@
+/*
+ * (C) 2007 by Sebastian Cla??en sebastian.clas...@freenet.ag
+ * (C) 2007-2010 by Jan Engelhardt jeng...@medozas.de
+ *
+ * Extracted from xt_TEE.c
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 or later, as
+ * published by the Free Software Foundation.
+ */
+#include linux/ip.h
+#include linux/module.h
+#include linux/percpu.h
+#include linux/route.h
+#include linux/skbuff.h
+#include net/checksum.h
+#include net/icmp.h
+#include net/ip.h
+#include net/route.h
+#include net/netfilter/ipv4/nf_dup_ipv4.h
+#if IS_ENABLED(CONFIG_NF_CONNTRACK)
+#include net/netfilter/nf_conntrack.h
+#endif
+
+static struct net *pick_net(struct sk_buff *skb)
+{
+#ifdef CONFIG_NET_NS
+   const struct dst_entry *dst;
+
+   if (skb-dev != NULL)
+   return dev_net(skb-dev);
+   dst = skb_dst(skb);
+   if (dst != NULL  dst-dev != NULL)
+   return dev_net(dst-dev);
+#endif
+   return init_net;
+}
+
+static bool nf_dup_ipv4_route(struct sk_buff *skb, const struct in_addr *gw,
+ int oif)
+{
+   const struct iphdr *iph = ip_hdr(skb);
+   struct net *net = pick_net(skb);
+   struct rtable *rt;
+   struct flowi4 fl4;
+
+   memset(fl4, 0, sizeof(fl4));
+   if (oif != -1)
+   fl4.flowi4_oif = oif;
+
+   fl4.daddr = gw-s_addr;
+   fl4.flowi4_tos = RT_TOS(iph-tos);
+   fl4.flowi4_scope = RT_SCOPE_UNIVERSE;
+   fl4.flowi4_flags = FLOWI_FLAG_KNOWN_NH;
+   rt = ip_route_output_key(net, fl4);
+   if (IS_ERR(rt))
+   return false;
+
+   skb_dst_drop(skb);
+   skb_dst_set(skb, rt-dst);
+   skb-dev  = rt-dst.dev;
+   skb-protocol = htons(ETH_P_IP);
+
+   return true;
+}
+
+void nf_dup_ipv4(struct sk_buff *skb, unsigned int hooknum,
+const struct in_addr