netdev.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 1/1] bridge: Fix NAT66ed IPv6 packets not being bridged correctly
@ 2014-09-15 21:27 Bernhard Thaler
  2014-09-15 21:40 ` David Miller
  0 siblings, 1 reply; 5+ messages in thread
From: Bernhard Thaler @ 2014-09-15 21:27 UTC (permalink / raw)
  To: davem, kuznet, jmorris, yoshfuji, kaber, stephen
  Cc: netdev, bridge, linux-kernel, Bernhard Thaler

Ethernet frames are not bridged to correct interface when packets have
been NAT66ed; compared to IPv4 logic in code, IPv6 code does not store
original address (before NAT) on transmit to determine if packet was
NAT66ed on receive to swap addresses back.

Changes added in br_netfilter.c to store original address, compare
against it and determine correct output interface. Changes needed in
netfilter_bridge.h to store IPv6 address in pre-existing union.
Export of ip6_route_input needed to use it in br_netfilter.c.

Problem may only affect systems doing NAT66 and ethernet bridging at
the same time. Tested in NAT66 setup on base of an ethernet bridge.

Signed-off-by: Bernhard Thaler <bernhard.thaler@wvnet.at>
---
 include/linux/netfilter_bridge.h |    2 +
 net/bridge/br_netfilter.c        |  136 ++++++++++++++++++++++++++++----------
 net/ipv6/route.c                 |    1 +
 3 files changed, 105 insertions(+), 34 deletions(-)

diff --git a/include/linux/netfilter_bridge.h b/include/linux/netfilter_bridge.h
index 8ab1c27..3a9cdcd 100644
--- a/include/linux/netfilter_bridge.h
+++ b/include/linux/netfilter_bridge.h
@@ -2,6 +2,7 @@
 #define __LINUX_BRIDGE_NETFILTER_H
 
 #include <uapi/linux/netfilter_bridge.h>
+#include <uapi/linux/in6.h>
 
 
 enum nf_br_hook_priorities {
@@ -79,6 +80,7 @@ static inline unsigned int nf_bridge_pad(const struct sk_buff *skb)
 struct bridge_skb_cb {
 	union {
 		__be32 ipv4;
+		struct in6_addr ipv6;
 	} daddr;
 };
 
diff --git a/net/bridge/br_netfilter.c b/net/bridge/br_netfilter.c
index a615264..2ae3888 100644
--- a/net/bridge/br_netfilter.c
+++ b/net/bridge/br_netfilter.c
@@ -35,6 +35,9 @@
 #include <net/ip.h>
 #include <net/ipv6.h>
 #include <net/route.h>
+#include <net/ip6_route.h>
+#include <net/flow.h>
+#include <net/dst.h>
 
 #include <asm/uaccess.h>
 #include "br_private.h"
@@ -42,10 +45,18 @@
 #include <linux/sysctl.h>
 #endif
 
-#define skb_origaddr(skb)	 (((struct bridge_skb_cb *) \
-				 (skb->nf_bridge->data))->daddr.ipv4)
-#define store_orig_dstaddr(skb)	 (skb_origaddr(skb) = ip_hdr(skb)->daddr)
-#define dnat_took_place(skb)	 (skb_origaddr(skb) != ip_hdr(skb)->daddr)
+#define skb_origaddr(skb)		(((struct bridge_skb_cb *)\
+					(skb->nf_bridge->data))->daddr.ipv4)
+#define skb_origaddr_ipv6(skb)		(((struct bridge_skb_cb *)\
+					(skb->nf_bridge->data))->daddr.ipv6)
+#define store_orig_dstaddr(skb)		(skb_origaddr(skb) = ip_hdr(skb)->daddr)
+#define store_orig_dstaddr_ipv6(skb)	(skb_origaddr_ipv6(skb) = \
+					ipv6_hdr(skb)->daddr)
+#define dnat_took_place(skb)		(skb_origaddr(skb) != \
+					ip_hdr(skb)->daddr)
+#define dnat_took_place_ipv6(skb)	(memcmp(&skb_origaddr_ipv6(skb), \
+					&(ipv6_hdr(skb)->daddr), \
+					sizeof(struct in6_addr)) != 0)
 
 #ifdef CONFIG_SYSCTL
 static struct ctl_table_header *brnf_sysctl_header;
@@ -340,36 +351,6 @@ int nf_bridge_copy_header(struct sk_buff *skb)
 	return 0;
 }
 
-/* PF_BRIDGE/PRE_ROUTING *********************************************/
-/* Undo the changes made for ip6tables PREROUTING and continue the
- * bridge PRE_ROUTING hook. */
-static int br_nf_pre_routing_finish_ipv6(struct sk_buff *skb)
-{
-	struct nf_bridge_info *nf_bridge = skb->nf_bridge;
-	struct rtable *rt;
-
-	if (nf_bridge->mask & BRNF_PKT_TYPE) {
-		skb->pkt_type = PACKET_OTHERHOST;
-		nf_bridge->mask ^= BRNF_PKT_TYPE;
-	}
-	nf_bridge->mask ^= BRNF_NF_BRIDGE_PREROUTING;
-
-	rt = bridge_parent_rtable(nf_bridge->physindev);
-	if (!rt) {
-		kfree_skb(skb);
-		return 0;
-	}
-	skb_dst_set_noref(skb, &rt->dst);
-
-	skb->dev = nf_bridge->physindev;
-	nf_bridge_update_protocol(skb);
-	nf_bridge_push_encap_header(skb);
-	NF_HOOK_THRESH(NFPROTO_BRIDGE, NF_BR_PRE_ROUTING, skb, skb->dev, NULL,
-		       br_handle_frame_finish, 1);
-
-	return 0;
-}
-
 /* Obtain the correct destination MAC address, while preserving the original
  * source MAC address. If we already know this address, we just copy it. If we
  * don't, we use the neighbour framework to find out. In both cases, we make
@@ -527,6 +508,92 @@ bridged_dnat:
 	return 0;
 }
 
+/* PF_BRIDGE/PRE_ROUTING *********************************************
+ * Undo the changes made for ip6tables PREROUTING and continue the
+ * bridge PRE_ROUTING hook.
+ */
+static int br_nf_pre_routing_finish_ipv6(struct sk_buff *skb)
+{
+	struct net_device *dev = skb->dev;
+	struct ipv6hdr *iph = ipv6_hdr(skb);
+	struct nf_bridge_info *nf_bridge = skb->nf_bridge;
+	struct rtable *rt;
+	struct dst_entry *dst;
+	struct flowi6 fl6 = {
+		.flowi6_iif = skb->dev->ifindex,
+		.daddr = iph->daddr,
+		.saddr = iph->saddr,
+		.flowlabel = ip6_flowinfo(iph),
+		.flowi6_mark = skb->mark,
+		.flowi6_proto = iph->nexthdr,
+	};
+
+	if (nf_bridge->mask & BRNF_PKT_TYPE) {
+		skb->pkt_type = PACKET_OTHERHOST;
+		nf_bridge->mask ^= BRNF_PKT_TYPE;
+	}
+	nf_bridge->mask ^= BRNF_NF_BRIDGE_PREROUTING;
+
+	if (dnat_took_place_ipv6(skb)) {
+		ip6_route_input(skb);
+		/* ip6_route_input is void function,
+		 * no int returned as in ip4_route_input
+		 * changes value of skb->_skb_refdst) on success
+		 */
+		if (skb->_skb_refdst == 0) {
+			struct in_device *in_dev = __in_dev_get_rcu(dev);
+
+			if (!in_dev || IN_DEV_FORWARD(in_dev))
+				goto free_skb;
+
+			dst = ip6_route_output(dev_net(dev), skb->sk, &fl6);
+			if (!IS_ERR(dst)) {
+				/* - Bridged-and-DNAT'ed traffic doesn't
+				 *   require ip_forwarding.
+				 */
+				if (dst->dev == dev) {
+					skb_dst_set(skb, dst);
+					goto bridged_dnat;
+				}
+				dst_release(dst);
+			}
+free_skb:
+			kfree_skb(skb);
+			return 0;
+		} else {
+			if (skb_dst(skb)->dev == dev) {
+bridged_dnat:
+				skb->dev = nf_bridge->physindev;
+				nf_bridge_update_protocol(skb);
+				nf_bridge_push_encap_header(skb);
+				NF_HOOK_THRESH(NFPROTO_BRIDGE,
+					       NF_BR_PRE_ROUTING,
+					       skb, skb->dev, NULL,
+					       br_nf_pre_routing_finish_bridge,
+					       1);
+				return 0;
+			}
+			memcpy(eth_hdr(skb)->h_dest, dev->dev_addr, ETH_ALEN);
+			skb->pkt_type = PACKET_HOST;
+		}
+	} else {
+		rt = bridge_parent_rtable(nf_bridge->physindev);
+		if (!rt) {
+			kfree_skb(skb);
+			return 0;
+		}
+		skb_dst_set_noref(skb, &rt->dst);
+	}
+
+	skb->dev = nf_bridge->physindev;
+	nf_bridge_update_protocol(skb);
+	nf_bridge_push_encap_header(skb);
+	NF_HOOK_THRESH(NFPROTO_BRIDGE, NF_BR_PRE_ROUTING, skb, skb->dev, NULL,
+		       br_handle_frame_finish, 1);
+
+	return 0;
+}
+
 static struct net_device *brnf_get_logical_dev(struct sk_buff *skb, const struct net_device *dev)
 {
 	struct net_device *vlan, *br;
@@ -658,6 +725,7 @@ static unsigned int br_nf_pre_routing_ipv6(const struct nf_hook_ops *ops,
 	if (!setup_pre_routing(skb))
 		return NF_DROP;
 
+	store_orig_dstaddr_ipv6(skb);
 	skb->protocol = htons(ETH_P_IPV6);
 	NF_HOOK(NFPROTO_IPV6, NF_INET_PRE_ROUTING, skb, skb->dev, NULL,
 		br_nf_pre_routing_finish_ipv6);
diff --git a/net/ipv6/route.c b/net/ipv6/route.c
index f23fbd2..e328905 100644
--- a/net/ipv6/route.c
+++ b/net/ipv6/route.c
@@ -1017,6 +1017,7 @@ void ip6_route_input(struct sk_buff *skb)
 
 	skb_dst_set(skb, ip6_route_input_lookup(net, skb->dev, &fl6, flags));
 }
+EXPORT_SYMBOL(ip6_route_input);
 
 static struct rt6_info *ip6_pol_route_output(struct net *net, struct fib6_table *table,
 					     struct flowi6 *fl6, int flags)
-- 
1.7.10.4

^ permalink raw reply related	[flat|nested] 5+ messages in thread

* Re: [PATCH 1/1] bridge: Fix NAT66ed IPv6 packets not being bridged correctly
  2014-09-15 21:27 [PATCH 1/1] bridge: Fix NAT66ed IPv6 packets not being bridged correctly Bernhard Thaler
@ 2014-09-15 21:40 ` David Miller
  2014-10-03 11:21   ` Pablo Neira Ayuso
  0 siblings, 1 reply; 5+ messages in thread
From: David Miller @ 2014-09-15 21:40 UTC (permalink / raw)
  To: bernhard.thaler
  Cc: yoshfuji, netdev, bridge, jmorris, linux-kernel, stephen,
	netfilter-devel, kuznet, kaber, pablo

From: Bernhard Thaler <bernhard.thaler@wvnet.at>
Date: Mon, 15 Sep 2014 23:27:28 +0200

CC:'ing netfilter-devel and the netfilter maintainer, which is
probably the primary place this patch should have been submitted.

> Ethernet frames are not bridged to correct interface when packets have
> been NAT66ed; compared to IPv4 logic in code, IPv6 code does not store
> original address (before NAT) on transmit to determine if packet was
> NAT66ed on receive to swap addresses back.
> 
> Changes added in br_netfilter.c to store original address, compare
> against it and determine correct output interface. Changes needed in
> netfilter_bridge.h to store IPv6 address in pre-existing union.
> Export of ip6_route_input needed to use it in br_netfilter.c.
> 
> Problem may only affect systems doing NAT66 and ethernet bridging at
> the same time. Tested in NAT66 setup on base of an ethernet bridge.
> 
> Signed-off-by: Bernhard Thaler <bernhard.thaler@wvnet.at>
> ---
>  include/linux/netfilter_bridge.h |    2 +
>  net/bridge/br_netfilter.c        |  136 ++++++++++++++++++++++++++++----------
>  net/ipv6/route.c                 |    1 +
>  3 files changed, 105 insertions(+), 34 deletions(-)
> 
> diff --git a/include/linux/netfilter_bridge.h b/include/linux/netfilter_bridge.h
> index 8ab1c27..3a9cdcd 100644
> --- a/include/linux/netfilter_bridge.h
> +++ b/include/linux/netfilter_bridge.h
> @@ -2,6 +2,7 @@
>  #define __LINUX_BRIDGE_NETFILTER_H
>  
>  #include <uapi/linux/netfilter_bridge.h>
> +#include <uapi/linux/in6.h>
>  
>  
>  enum nf_br_hook_priorities {
> @@ -79,6 +80,7 @@ static inline unsigned int nf_bridge_pad(const struct sk_buff *skb)
>  struct bridge_skb_cb {
>  	union {
>  		__be32 ipv4;
> +		struct in6_addr ipv6;
>  	} daddr;
>  };
>  
> diff --git a/net/bridge/br_netfilter.c b/net/bridge/br_netfilter.c
> index a615264..2ae3888 100644
> --- a/net/bridge/br_netfilter.c
> +++ b/net/bridge/br_netfilter.c
> @@ -35,6 +35,9 @@
>  #include <net/ip.h>
>  #include <net/ipv6.h>
>  #include <net/route.h>
> +#include <net/ip6_route.h>
> +#include <net/flow.h>
> +#include <net/dst.h>
>  
>  #include <asm/uaccess.h>
>  #include "br_private.h"
> @@ -42,10 +45,18 @@
>  #include <linux/sysctl.h>
>  #endif
>  
> -#define skb_origaddr(skb)	 (((struct bridge_skb_cb *) \
> -				 (skb->nf_bridge->data))->daddr.ipv4)
> -#define store_orig_dstaddr(skb)	 (skb_origaddr(skb) = ip_hdr(skb)->daddr)
> -#define dnat_took_place(skb)	 (skb_origaddr(skb) != ip_hdr(skb)->daddr)
> +#define skb_origaddr(skb)		(((struct bridge_skb_cb *)\
> +					(skb->nf_bridge->data))->daddr.ipv4)
> +#define skb_origaddr_ipv6(skb)		(((struct bridge_skb_cb *)\
> +					(skb->nf_bridge->data))->daddr.ipv6)
> +#define store_orig_dstaddr(skb)		(skb_origaddr(skb) = ip_hdr(skb)->daddr)
> +#define store_orig_dstaddr_ipv6(skb)	(skb_origaddr_ipv6(skb) = \
> +					ipv6_hdr(skb)->daddr)
> +#define dnat_took_place(skb)		(skb_origaddr(skb) != \
> +					ip_hdr(skb)->daddr)
> +#define dnat_took_place_ipv6(skb)	(memcmp(&skb_origaddr_ipv6(skb), \
> +					&(ipv6_hdr(skb)->daddr), \
> +					sizeof(struct in6_addr)) != 0)
>  
>  #ifdef CONFIG_SYSCTL
>  static struct ctl_table_header *brnf_sysctl_header;
> @@ -340,36 +351,6 @@ int nf_bridge_copy_header(struct sk_buff *skb)
>  	return 0;
>  }
>  
> -/* PF_BRIDGE/PRE_ROUTING *********************************************/
> -/* Undo the changes made for ip6tables PREROUTING and continue the
> - * bridge PRE_ROUTING hook. */
> -static int br_nf_pre_routing_finish_ipv6(struct sk_buff *skb)
> -{
> -	struct nf_bridge_info *nf_bridge = skb->nf_bridge;
> -	struct rtable *rt;
> -
> -	if (nf_bridge->mask & BRNF_PKT_TYPE) {
> -		skb->pkt_type = PACKET_OTHERHOST;
> -		nf_bridge->mask ^= BRNF_PKT_TYPE;
> -	}
> -	nf_bridge->mask ^= BRNF_NF_BRIDGE_PREROUTING;
> -
> -	rt = bridge_parent_rtable(nf_bridge->physindev);
> -	if (!rt) {
> -		kfree_skb(skb);
> -		return 0;
> -	}
> -	skb_dst_set_noref(skb, &rt->dst);
> -
> -	skb->dev = nf_bridge->physindev;
> -	nf_bridge_update_protocol(skb);
> -	nf_bridge_push_encap_header(skb);
> -	NF_HOOK_THRESH(NFPROTO_BRIDGE, NF_BR_PRE_ROUTING, skb, skb->dev, NULL,
> -		       br_handle_frame_finish, 1);
> -
> -	return 0;
> -}
> -
>  /* Obtain the correct destination MAC address, while preserving the original
>   * source MAC address. If we already know this address, we just copy it. If we
>   * don't, we use the neighbour framework to find out. In both cases, we make
> @@ -527,6 +508,92 @@ bridged_dnat:
>  	return 0;
>  }
>  
> +/* PF_BRIDGE/PRE_ROUTING *********************************************
> + * Undo the changes made for ip6tables PREROUTING and continue the
> + * bridge PRE_ROUTING hook.
> + */
> +static int br_nf_pre_routing_finish_ipv6(struct sk_buff *skb)
> +{
> +	struct net_device *dev = skb->dev;
> +	struct ipv6hdr *iph = ipv6_hdr(skb);
> +	struct nf_bridge_info *nf_bridge = skb->nf_bridge;
> +	struct rtable *rt;
> +	struct dst_entry *dst;
> +	struct flowi6 fl6 = {
> +		.flowi6_iif = skb->dev->ifindex,
> +		.daddr = iph->daddr,
> +		.saddr = iph->saddr,
> +		.flowlabel = ip6_flowinfo(iph),
> +		.flowi6_mark = skb->mark,
> +		.flowi6_proto = iph->nexthdr,
> +	};
> +
> +	if (nf_bridge->mask & BRNF_PKT_TYPE) {
> +		skb->pkt_type = PACKET_OTHERHOST;
> +		nf_bridge->mask ^= BRNF_PKT_TYPE;
> +	}
> +	nf_bridge->mask ^= BRNF_NF_BRIDGE_PREROUTING;
> +
> +	if (dnat_took_place_ipv6(skb)) {
> +		ip6_route_input(skb);
> +		/* ip6_route_input is void function,
> +		 * no int returned as in ip4_route_input
> +		 * changes value of skb->_skb_refdst) on success
> +		 */
> +		if (skb->_skb_refdst == 0) {
> +			struct in_device *in_dev = __in_dev_get_rcu(dev);
> +
> +			if (!in_dev || IN_DEV_FORWARD(in_dev))
> +				goto free_skb;
> +
> +			dst = ip6_route_output(dev_net(dev), skb->sk, &fl6);
> +			if (!IS_ERR(dst)) {
> +				/* - Bridged-and-DNAT'ed traffic doesn't
> +				 *   require ip_forwarding.
> +				 */
> +				if (dst->dev == dev) {
> +					skb_dst_set(skb, dst);
> +					goto bridged_dnat;
> +				}
> +				dst_release(dst);
> +			}
> +free_skb:
> +			kfree_skb(skb);
> +			return 0;
> +		} else {
> +			if (skb_dst(skb)->dev == dev) {
> +bridged_dnat:
> +				skb->dev = nf_bridge->physindev;
> +				nf_bridge_update_protocol(skb);
> +				nf_bridge_push_encap_header(skb);
> +				NF_HOOK_THRESH(NFPROTO_BRIDGE,
> +					       NF_BR_PRE_ROUTING,
> +					       skb, skb->dev, NULL,
> +					       br_nf_pre_routing_finish_bridge,
> +					       1);
> +				return 0;
> +			}
> +			memcpy(eth_hdr(skb)->h_dest, dev->dev_addr, ETH_ALEN);
> +			skb->pkt_type = PACKET_HOST;
> +		}
> +	} else {
> +		rt = bridge_parent_rtable(nf_bridge->physindev);
> +		if (!rt) {
> +			kfree_skb(skb);
> +			return 0;
> +		}
> +		skb_dst_set_noref(skb, &rt->dst);
> +	}
> +
> +	skb->dev = nf_bridge->physindev;
> +	nf_bridge_update_protocol(skb);
> +	nf_bridge_push_encap_header(skb);
> +	NF_HOOK_THRESH(NFPROTO_BRIDGE, NF_BR_PRE_ROUTING, skb, skb->dev, NULL,
> +		       br_handle_frame_finish, 1);
> +
> +	return 0;
> +}
> +
>  static struct net_device *brnf_get_logical_dev(struct sk_buff *skb, const struct net_device *dev)
>  {
>  	struct net_device *vlan, *br;
> @@ -658,6 +725,7 @@ static unsigned int br_nf_pre_routing_ipv6(const struct nf_hook_ops *ops,
>  	if (!setup_pre_routing(skb))
>  		return NF_DROP;
>  
> +	store_orig_dstaddr_ipv6(skb);
>  	skb->protocol = htons(ETH_P_IPV6);
>  	NF_HOOK(NFPROTO_IPV6, NF_INET_PRE_ROUTING, skb, skb->dev, NULL,
>  		br_nf_pre_routing_finish_ipv6);
> diff --git a/net/ipv6/route.c b/net/ipv6/route.c
> index f23fbd2..e328905 100644
> --- a/net/ipv6/route.c
> +++ b/net/ipv6/route.c
> @@ -1017,6 +1017,7 @@ void ip6_route_input(struct sk_buff *skb)
>  
>  	skb_dst_set(skb, ip6_route_input_lookup(net, skb->dev, &fl6, flags));
>  }
> +EXPORT_SYMBOL(ip6_route_input);
>  
>  static struct rt6_info *ip6_pol_route_output(struct net *net, struct fib6_table *table,
>  					     struct flowi6 *fl6, int flags)
> -- 
> 1.7.10.4
> 

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH 1/1] bridge: Fix NAT66ed IPv6 packets not being bridged correctly
  2014-09-15 21:40 ` David Miller
@ 2014-10-03 11:21   ` Pablo Neira Ayuso
  2014-11-27 19:26     ` Bernhard Thaler
  0 siblings, 1 reply; 5+ messages in thread
From: Pablo Neira Ayuso @ 2014-10-03 11:21 UTC (permalink / raw)
  To: bernhard.thaler
  Cc: David Miller, kuznet, jmorris, yoshfuji, kaber, stephen, netdev,
	bridge, linux-kernel, netfilter-devel, sven

Hi Bernhard,

Sorry for taking a bit to get back to you with feedback. We've been
discussing recently some changes in br_netfilter. Basically, to
modularize it [1] and this has taken a while.

Regarding your change. Sven Eckelmann (CC'ed in this email) sent a RFC
out of the merge window that have remain tagged in my patchwork, you
can find it here.

http://patchwork.ozlabs.org/patch/381027/

I would like to see a submission that covers all NAT66 scenarios that
we currenty support.

Thanks.

[1] http://comments.gmane.org/gmane.comp.security.firewalls.netfilter.devel/54234

On Mon, Sep 15, 2014 at 05:40:09PM -0400, David Miller wrote:
> From: Bernhard Thaler <bernhard.thaler@wvnet.at>
> Date: Mon, 15 Sep 2014 23:27:28 +0200
> 
> CC:'ing netfilter-devel and the netfilter maintainer, which is
> probably the primary place this patch should have been submitted.
> 
> > Ethernet frames are not bridged to correct interface when packets have
> > been NAT66ed; compared to IPv4 logic in code, IPv6 code does not store
> > original address (before NAT) on transmit to determine if packet was
> > NAT66ed on receive to swap addresses back.
> > 
> > Changes added in br_netfilter.c to store original address, compare
> > against it and determine correct output interface. Changes needed in
> > netfilter_bridge.h to store IPv6 address in pre-existing union.
> > Export of ip6_route_input needed to use it in br_netfilter.c.
> > 
> > Problem may only affect systems doing NAT66 and ethernet bridging at
> > the same time. Tested in NAT66 setup on base of an ethernet bridge.
> > 
> > Signed-off-by: Bernhard Thaler <bernhard.thaler@wvnet.at>
> > ---
> >  include/linux/netfilter_bridge.h |    2 +
> >  net/bridge/br_netfilter.c        |  136 ++++++++++++++++++++++++++++----------
> >  net/ipv6/route.c                 |    1 +
> >  3 files changed, 105 insertions(+), 34 deletions(-)
> > 
> > diff --git a/include/linux/netfilter_bridge.h b/include/linux/netfilter_bridge.h
> > index 8ab1c27..3a9cdcd 100644
> > --- a/include/linux/netfilter_bridge.h
> > +++ b/include/linux/netfilter_bridge.h
> > @@ -2,6 +2,7 @@
> >  #define __LINUX_BRIDGE_NETFILTER_H
> >  
> >  #include <uapi/linux/netfilter_bridge.h>
> > +#include <uapi/linux/in6.h>
> >  
> >  
> >  enum nf_br_hook_priorities {
> > @@ -79,6 +80,7 @@ static inline unsigned int nf_bridge_pad(const struct sk_buff *skb)
> >  struct bridge_skb_cb {
> >  	union {
> >  		__be32 ipv4;
> > +		struct in6_addr ipv6;
> >  	} daddr;
> >  };
> >  
> > diff --git a/net/bridge/br_netfilter.c b/net/bridge/br_netfilter.c
> > index a615264..2ae3888 100644
> > --- a/net/bridge/br_netfilter.c
> > +++ b/net/bridge/br_netfilter.c
> > @@ -35,6 +35,9 @@
> >  #include <net/ip.h>
> >  #include <net/ipv6.h>
> >  #include <net/route.h>
> > +#include <net/ip6_route.h>
> > +#include <net/flow.h>
> > +#include <net/dst.h>
> >  
> >  #include <asm/uaccess.h>
> >  #include "br_private.h"
> > @@ -42,10 +45,18 @@
> >  #include <linux/sysctl.h>
> >  #endif
> >  
> > -#define skb_origaddr(skb)	 (((struct bridge_skb_cb *) \
> > -				 (skb->nf_bridge->data))->daddr.ipv4)
> > -#define store_orig_dstaddr(skb)	 (skb_origaddr(skb) = ip_hdr(skb)->daddr)
> > -#define dnat_took_place(skb)	 (skb_origaddr(skb) != ip_hdr(skb)->daddr)
> > +#define skb_origaddr(skb)		(((struct bridge_skb_cb *)\
> > +					(skb->nf_bridge->data))->daddr.ipv4)
> > +#define skb_origaddr_ipv6(skb)		(((struct bridge_skb_cb *)\
> > +					(skb->nf_bridge->data))->daddr.ipv6)
> > +#define store_orig_dstaddr(skb)		(skb_origaddr(skb) = ip_hdr(skb)->daddr)
> > +#define store_orig_dstaddr_ipv6(skb)	(skb_origaddr_ipv6(skb) = \
> > +					ipv6_hdr(skb)->daddr)
> > +#define dnat_took_place(skb)		(skb_origaddr(skb) != \
> > +					ip_hdr(skb)->daddr)
> > +#define dnat_took_place_ipv6(skb)	(memcmp(&skb_origaddr_ipv6(skb), \
> > +					&(ipv6_hdr(skb)->daddr), \
> > +					sizeof(struct in6_addr)) != 0)
> >  
> >  #ifdef CONFIG_SYSCTL
> >  static struct ctl_table_header *brnf_sysctl_header;
> > @@ -340,36 +351,6 @@ int nf_bridge_copy_header(struct sk_buff *skb)
> >  	return 0;
> >  }
> >  
> > -/* PF_BRIDGE/PRE_ROUTING *********************************************/
> > -/* Undo the changes made for ip6tables PREROUTING and continue the
> > - * bridge PRE_ROUTING hook. */
> > -static int br_nf_pre_routing_finish_ipv6(struct sk_buff *skb)
> > -{
> > -	struct nf_bridge_info *nf_bridge = skb->nf_bridge;
> > -	struct rtable *rt;
> > -
> > -	if (nf_bridge->mask & BRNF_PKT_TYPE) {
> > -		skb->pkt_type = PACKET_OTHERHOST;
> > -		nf_bridge->mask ^= BRNF_PKT_TYPE;
> > -	}
> > -	nf_bridge->mask ^= BRNF_NF_BRIDGE_PREROUTING;
> > -
> > -	rt = bridge_parent_rtable(nf_bridge->physindev);
> > -	if (!rt) {
> > -		kfree_skb(skb);
> > -		return 0;
> > -	}
> > -	skb_dst_set_noref(skb, &rt->dst);
> > -
> > -	skb->dev = nf_bridge->physindev;
> > -	nf_bridge_update_protocol(skb);
> > -	nf_bridge_push_encap_header(skb);
> > -	NF_HOOK_THRESH(NFPROTO_BRIDGE, NF_BR_PRE_ROUTING, skb, skb->dev, NULL,
> > -		       br_handle_frame_finish, 1);
> > -
> > -	return 0;
> > -}
> > -
> >  /* Obtain the correct destination MAC address, while preserving the original
> >   * source MAC address. If we already know this address, we just copy it. If we
> >   * don't, we use the neighbour framework to find out. In both cases, we make
> > @@ -527,6 +508,92 @@ bridged_dnat:
> >  	return 0;
> >  }
> >  
> > +/* PF_BRIDGE/PRE_ROUTING *********************************************
> > + * Undo the changes made for ip6tables PREROUTING and continue the
> > + * bridge PRE_ROUTING hook.
> > + */
> > +static int br_nf_pre_routing_finish_ipv6(struct sk_buff *skb)
> > +{
> > +	struct net_device *dev = skb->dev;
> > +	struct ipv6hdr *iph = ipv6_hdr(skb);
> > +	struct nf_bridge_info *nf_bridge = skb->nf_bridge;
> > +	struct rtable *rt;
> > +	struct dst_entry *dst;
> > +	struct flowi6 fl6 = {
> > +		.flowi6_iif = skb->dev->ifindex,
> > +		.daddr = iph->daddr,
> > +		.saddr = iph->saddr,
> > +		.flowlabel = ip6_flowinfo(iph),
> > +		.flowi6_mark = skb->mark,
> > +		.flowi6_proto = iph->nexthdr,
> > +	};
> > +
> > +	if (nf_bridge->mask & BRNF_PKT_TYPE) {
> > +		skb->pkt_type = PACKET_OTHERHOST;
> > +		nf_bridge->mask ^= BRNF_PKT_TYPE;
> > +	}
> > +	nf_bridge->mask ^= BRNF_NF_BRIDGE_PREROUTING;
> > +
> > +	if (dnat_took_place_ipv6(skb)) {
> > +		ip6_route_input(skb);
> > +		/* ip6_route_input is void function,
> > +		 * no int returned as in ip4_route_input
> > +		 * changes value of skb->_skb_refdst) on success
> > +		 */
> > +		if (skb->_skb_refdst == 0) {
> > +			struct in_device *in_dev = __in_dev_get_rcu(dev);
> > +
> > +			if (!in_dev || IN_DEV_FORWARD(in_dev))
> > +				goto free_skb;
> > +
> > +			dst = ip6_route_output(dev_net(dev), skb->sk, &fl6);
> > +			if (!IS_ERR(dst)) {
> > +				/* - Bridged-and-DNAT'ed traffic doesn't
> > +				 *   require ip_forwarding.
> > +				 */
> > +				if (dst->dev == dev) {
> > +					skb_dst_set(skb, dst);
> > +					goto bridged_dnat;
> > +				}
> > +				dst_release(dst);
> > +			}
> > +free_skb:
> > +			kfree_skb(skb);
> > +			return 0;
> > +		} else {
> > +			if (skb_dst(skb)->dev == dev) {
> > +bridged_dnat:
> > +				skb->dev = nf_bridge->physindev;
> > +				nf_bridge_update_protocol(skb);
> > +				nf_bridge_push_encap_header(skb);
> > +				NF_HOOK_THRESH(NFPROTO_BRIDGE,
> > +					       NF_BR_PRE_ROUTING,
> > +					       skb, skb->dev, NULL,
> > +					       br_nf_pre_routing_finish_bridge,
> > +					       1);
> > +				return 0;
> > +			}
> > +			memcpy(eth_hdr(skb)->h_dest, dev->dev_addr, ETH_ALEN);
> > +			skb->pkt_type = PACKET_HOST;
> > +		}
> > +	} else {
> > +		rt = bridge_parent_rtable(nf_bridge->physindev);
> > +		if (!rt) {
> > +			kfree_skb(skb);
> > +			return 0;
> > +		}
> > +		skb_dst_set_noref(skb, &rt->dst);
> > +	}
> > +
> > +	skb->dev = nf_bridge->physindev;
> > +	nf_bridge_update_protocol(skb);
> > +	nf_bridge_push_encap_header(skb);
> > +	NF_HOOK_THRESH(NFPROTO_BRIDGE, NF_BR_PRE_ROUTING, skb, skb->dev, NULL,
> > +		       br_handle_frame_finish, 1);
> > +
> > +	return 0;
> > +}
> > +
> >  static struct net_device *brnf_get_logical_dev(struct sk_buff *skb, const struct net_device *dev)
> >  {
> >  	struct net_device *vlan, *br;
> > @@ -658,6 +725,7 @@ static unsigned int br_nf_pre_routing_ipv6(const struct nf_hook_ops *ops,
> >  	if (!setup_pre_routing(skb))
> >  		return NF_DROP;
> >  
> > +	store_orig_dstaddr_ipv6(skb);
> >  	skb->protocol = htons(ETH_P_IPV6);
> >  	NF_HOOK(NFPROTO_IPV6, NF_INET_PRE_ROUTING, skb, skb->dev, NULL,
> >  		br_nf_pre_routing_finish_ipv6);
> > diff --git a/net/ipv6/route.c b/net/ipv6/route.c
> > index f23fbd2..e328905 100644
> > --- a/net/ipv6/route.c
> > +++ b/net/ipv6/route.c
> > @@ -1017,6 +1017,7 @@ void ip6_route_input(struct sk_buff *skb)
> >  
> >  	skb_dst_set(skb, ip6_route_input_lookup(net, skb->dev, &fl6, flags));
> >  }
> > +EXPORT_SYMBOL(ip6_route_input);
> >  
> >  static struct rt6_info *ip6_pol_route_output(struct net *net, struct fib6_table *table,
> >  					     struct flowi6 *fl6, int flags)
> > -- 
> > 1.7.10.4
> > 

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH 1/1] bridge: Fix NAT66ed IPv6 packets not being bridged correctly
  2014-10-03 11:21   ` Pablo Neira Ayuso
@ 2014-11-27 19:26     ` Bernhard Thaler
  2014-11-28 17:55       ` Pablo Neira Ayuso
  0 siblings, 1 reply; 5+ messages in thread
From: Bernhard Thaler @ 2014-11-27 19:26 UTC (permalink / raw)
  To: Pablo Neira Ayuso
  Cc: sven, yoshfuji, netdev, bridge, jmorris, David Miller,
	netfilter-devel, kuznet, kaber, linux-kernel

Hi,

I tested Sven's patch in my setup and I think it should be safe to use
it. It is shorter and cleaner written and he submitted it earlier.

I will be happy to assist you or Sven if any further work is needed.

Regards,
Bernhard

On 03.10.2014 13:21, Pablo Neira Ayuso wrote:
> Hi Bernhard,
> 
> Sorry for taking a bit to get back to you with feedback. We've been
> discussing recently some changes in br_netfilter. Basically, to
> modularize it [1] and this has taken a while.
> 
> Regarding your change. Sven Eckelmann (CC'ed in this email) sent a RFC
> out of the merge window that have remain tagged in my patchwork, you
> can find it here.
> 
> http://patchwork.ozlabs.org/patch/381027/
> 
> I would like to see a submission that covers all NAT66 scenarios that
> we currenty support.
> 
> Thanks.
> 
> [1] http://comments.gmane.org/gmane.comp.security.firewalls.netfilter.devel/54234
> 
> On Mon, Sep 15, 2014 at 05:40:09PM -0400, David Miller wrote:
>> From: Bernhard Thaler <bernhard.thaler@wvnet.at>
>> Date: Mon, 15 Sep 2014 23:27:28 +0200
>>
>> CC:'ing netfilter-devel and the netfilter maintainer, which is
>> probably the primary place this patch should have been submitted.
>>
>>> Ethernet frames are not bridged to correct interface when packets have
>>> been NAT66ed; compared to IPv4 logic in code, IPv6 code does not store
>>> original address (before NAT) on transmit to determine if packet was
>>> NAT66ed on receive to swap addresses back.
>>>
>>> Changes added in br_netfilter.c to store original address, compare
>>> against it and determine correct output interface. Changes needed in
>>> netfilter_bridge.h to store IPv6 address in pre-existing union.
>>> Export of ip6_route_input needed to use it in br_netfilter.c.
>>>
>>> Problem may only affect systems doing NAT66 and ethernet bridging at
>>> the same time. Tested in NAT66 setup on base of an ethernet bridge.
>>>
>>> Signed-off-by: Bernhard Thaler <bernhard.thaler@wvnet.at>
>>> ---
>>>  include/linux/netfilter_bridge.h |    2 +
>>>  net/bridge/br_netfilter.c        |  136 ++++++++++++++++++++++++++++----------
>>>  net/ipv6/route.c                 |    1 +
>>>  3 files changed, 105 insertions(+), 34 deletions(-)
>>>
>>> diff --git a/include/linux/netfilter_bridge.h b/include/linux/netfilter_bridge.h
>>> index 8ab1c27..3a9cdcd 100644
>>> --- a/include/linux/netfilter_bridge.h
>>> +++ b/include/linux/netfilter_bridge.h
>>> @@ -2,6 +2,7 @@
>>>  #define __LINUX_BRIDGE_NETFILTER_H
>>>  
>>>  #include <uapi/linux/netfilter_bridge.h>
>>> +#include <uapi/linux/in6.h>
>>>  
>>>  
>>>  enum nf_br_hook_priorities {
>>> @@ -79,6 +80,7 @@ static inline unsigned int nf_bridge_pad(const struct sk_buff *skb)
>>>  struct bridge_skb_cb {
>>>  	union {
>>>  		__be32 ipv4;
>>> +		struct in6_addr ipv6;
>>>  	} daddr;
>>>  };
>>>  
>>> diff --git a/net/bridge/br_netfilter.c b/net/bridge/br_netfilter.c
>>> index a615264..2ae3888 100644
>>> --- a/net/bridge/br_netfilter.c
>>> +++ b/net/bridge/br_netfilter.c
>>> @@ -35,6 +35,9 @@
>>>  #include <net/ip.h>
>>>  #include <net/ipv6.h>
>>>  #include <net/route.h>
>>> +#include <net/ip6_route.h>
>>> +#include <net/flow.h>
>>> +#include <net/dst.h>
>>>  
>>>  #include <asm/uaccess.h>
>>>  #include "br_private.h"
>>> @@ -42,10 +45,18 @@
>>>  #include <linux/sysctl.h>
>>>  #endif
>>>  
>>> -#define skb_origaddr(skb)	 (((struct bridge_skb_cb *) \
>>> -				 (skb->nf_bridge->data))->daddr.ipv4)
>>> -#define store_orig_dstaddr(skb)	 (skb_origaddr(skb) = ip_hdr(skb)->daddr)
>>> -#define dnat_took_place(skb)	 (skb_origaddr(skb) != ip_hdr(skb)->daddr)
>>> +#define skb_origaddr(skb)		(((struct bridge_skb_cb *)\
>>> +					(skb->nf_bridge->data))->daddr.ipv4)
>>> +#define skb_origaddr_ipv6(skb)		(((struct bridge_skb_cb *)\
>>> +					(skb->nf_bridge->data))->daddr.ipv6)
>>> +#define store_orig_dstaddr(skb)		(skb_origaddr(skb) = ip_hdr(skb)->daddr)
>>> +#define store_orig_dstaddr_ipv6(skb)	(skb_origaddr_ipv6(skb) = \
>>> +					ipv6_hdr(skb)->daddr)
>>> +#define dnat_took_place(skb)		(skb_origaddr(skb) != \
>>> +					ip_hdr(skb)->daddr)
>>> +#define dnat_took_place_ipv6(skb)	(memcmp(&skb_origaddr_ipv6(skb), \
>>> +					&(ipv6_hdr(skb)->daddr), \
>>> +					sizeof(struct in6_addr)) != 0)
>>>  
>>>  #ifdef CONFIG_SYSCTL
>>>  static struct ctl_table_header *brnf_sysctl_header;
>>> @@ -340,36 +351,6 @@ int nf_bridge_copy_header(struct sk_buff *skb)
>>>  	return 0;
>>>  }
>>>  
>>> -/* PF_BRIDGE/PRE_ROUTING *********************************************/
>>> -/* Undo the changes made for ip6tables PREROUTING and continue the
>>> - * bridge PRE_ROUTING hook. */
>>> -static int br_nf_pre_routing_finish_ipv6(struct sk_buff *skb)
>>> -{
>>> -	struct nf_bridge_info *nf_bridge = skb->nf_bridge;
>>> -	struct rtable *rt;
>>> -
>>> -	if (nf_bridge->mask & BRNF_PKT_TYPE) {
>>> -		skb->pkt_type = PACKET_OTHERHOST;
>>> -		nf_bridge->mask ^= BRNF_PKT_TYPE;
>>> -	}
>>> -	nf_bridge->mask ^= BRNF_NF_BRIDGE_PREROUTING;
>>> -
>>> -	rt = bridge_parent_rtable(nf_bridge->physindev);
>>> -	if (!rt) {
>>> -		kfree_skb(skb);
>>> -		return 0;
>>> -	}
>>> -	skb_dst_set_noref(skb, &rt->dst);
>>> -
>>> -	skb->dev = nf_bridge->physindev;
>>> -	nf_bridge_update_protocol(skb);
>>> -	nf_bridge_push_encap_header(skb);
>>> -	NF_HOOK_THRESH(NFPROTO_BRIDGE, NF_BR_PRE_ROUTING, skb, skb->dev, NULL,
>>> -		       br_handle_frame_finish, 1);
>>> -
>>> -	return 0;
>>> -}
>>> -
>>>  /* Obtain the correct destination MAC address, while preserving the original
>>>   * source MAC address. If we already know this address, we just copy it. If we
>>>   * don't, we use the neighbour framework to find out. In both cases, we make
>>> @@ -527,6 +508,92 @@ bridged_dnat:
>>>  	return 0;
>>>  }
>>>  
>>> +/* PF_BRIDGE/PRE_ROUTING *********************************************
>>> + * Undo the changes made for ip6tables PREROUTING and continue the
>>> + * bridge PRE_ROUTING hook.
>>> + */
>>> +static int br_nf_pre_routing_finish_ipv6(struct sk_buff *skb)
>>> +{
>>> +	struct net_device *dev = skb->dev;
>>> +	struct ipv6hdr *iph = ipv6_hdr(skb);
>>> +	struct nf_bridge_info *nf_bridge = skb->nf_bridge;
>>> +	struct rtable *rt;
>>> +	struct dst_entry *dst;
>>> +	struct flowi6 fl6 = {
>>> +		.flowi6_iif = skb->dev->ifindex,
>>> +		.daddr = iph->daddr,
>>> +		.saddr = iph->saddr,
>>> +		.flowlabel = ip6_flowinfo(iph),
>>> +		.flowi6_mark = skb->mark,
>>> +		.flowi6_proto = iph->nexthdr,
>>> +	};
>>> +
>>> +	if (nf_bridge->mask & BRNF_PKT_TYPE) {
>>> +		skb->pkt_type = PACKET_OTHERHOST;
>>> +		nf_bridge->mask ^= BRNF_PKT_TYPE;
>>> +	}
>>> +	nf_bridge->mask ^= BRNF_NF_BRIDGE_PREROUTING;
>>> +
>>> +	if (dnat_took_place_ipv6(skb)) {
>>> +		ip6_route_input(skb);
>>> +		/* ip6_route_input is void function,
>>> +		 * no int returned as in ip4_route_input
>>> +		 * changes value of skb->_skb_refdst) on success
>>> +		 */
>>> +		if (skb->_skb_refdst == 0) {
>>> +			struct in_device *in_dev = __in_dev_get_rcu(dev);
>>> +
>>> +			if (!in_dev || IN_DEV_FORWARD(in_dev))
>>> +				goto free_skb;
>>> +
>>> +			dst = ip6_route_output(dev_net(dev), skb->sk, &fl6);
>>> +			if (!IS_ERR(dst)) {
>>> +				/* - Bridged-and-DNAT'ed traffic doesn't
>>> +				 *   require ip_forwarding.
>>> +				 */
>>> +				if (dst->dev == dev) {
>>> +					skb_dst_set(skb, dst);
>>> +					goto bridged_dnat;
>>> +				}
>>> +				dst_release(dst);
>>> +			}
>>> +free_skb:
>>> +			kfree_skb(skb);
>>> +			return 0;
>>> +		} else {
>>> +			if (skb_dst(skb)->dev == dev) {
>>> +bridged_dnat:
>>> +				skb->dev = nf_bridge->physindev;
>>> +				nf_bridge_update_protocol(skb);
>>> +				nf_bridge_push_encap_header(skb);
>>> +				NF_HOOK_THRESH(NFPROTO_BRIDGE,
>>> +					       NF_BR_PRE_ROUTING,
>>> +					       skb, skb->dev, NULL,
>>> +					       br_nf_pre_routing_finish_bridge,
>>> +					       1);
>>> +				return 0;
>>> +			}
>>> +			memcpy(eth_hdr(skb)->h_dest, dev->dev_addr, ETH_ALEN);
>>> +			skb->pkt_type = PACKET_HOST;
>>> +		}
>>> +	} else {
>>> +		rt = bridge_parent_rtable(nf_bridge->physindev);
>>> +		if (!rt) {
>>> +			kfree_skb(skb);
>>> +			return 0;
>>> +		}
>>> +		skb_dst_set_noref(skb, &rt->dst);
>>> +	}
>>> +
>>> +	skb->dev = nf_bridge->physindev;
>>> +	nf_bridge_update_protocol(skb);
>>> +	nf_bridge_push_encap_header(skb);
>>> +	NF_HOOK_THRESH(NFPROTO_BRIDGE, NF_BR_PRE_ROUTING, skb, skb->dev, NULL,
>>> +		       br_handle_frame_finish, 1);
>>> +
>>> +	return 0;
>>> +}
>>> +
>>>  static struct net_device *brnf_get_logical_dev(struct sk_buff *skb, const struct net_device *dev)
>>>  {
>>>  	struct net_device *vlan, *br;
>>> @@ -658,6 +725,7 @@ static unsigned int br_nf_pre_routing_ipv6(const struct nf_hook_ops *ops,
>>>  	if (!setup_pre_routing(skb))
>>>  		return NF_DROP;
>>>  
>>> +	store_orig_dstaddr_ipv6(skb);
>>>  	skb->protocol = htons(ETH_P_IPV6);
>>>  	NF_HOOK(NFPROTO_IPV6, NF_INET_PRE_ROUTING, skb, skb->dev, NULL,
>>>  		br_nf_pre_routing_finish_ipv6);
>>> diff --git a/net/ipv6/route.c b/net/ipv6/route.c
>>> index f23fbd2..e328905 100644
>>> --- a/net/ipv6/route.c
>>> +++ b/net/ipv6/route.c
>>> @@ -1017,6 +1017,7 @@ void ip6_route_input(struct sk_buff *skb)
>>>  
>>>  	skb_dst_set(skb, ip6_route_input_lookup(net, skb->dev, &fl6, flags));
>>>  }
>>> +EXPORT_SYMBOL(ip6_route_input);
>>>  
>>>  static struct rt6_info *ip6_pol_route_output(struct net *net, struct fib6_table *table,
>>>  					     struct flowi6 *fl6, int flags)
>>> -- 
>>> 1.7.10.4
>>>

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH 1/1] bridge: Fix NAT66ed IPv6 packets not being bridged correctly
  2014-11-27 19:26     ` Bernhard Thaler
@ 2014-11-28 17:55       ` Pablo Neira Ayuso
  0 siblings, 0 replies; 5+ messages in thread
From: Pablo Neira Ayuso @ 2014-11-28 17:55 UTC (permalink / raw)
  To: Bernhard Thaler
  Cc: sven, yoshfuji, netdev, bridge, jmorris, David Miller,
	netfilter-devel, kuznet, kaber, linux-kernel

On Thu, Nov 27, 2014 at 08:26:30PM +0100, Bernhard Thaler wrote:
> Hi,
> 
> I tested Sven's patch in my setup and I think it should be safe to use
> it. It is shorter and cleaner written and he submitted it earlier.

Thanks for testing.

> I will be happy to assist you or Sven if any further work is needed.

Please, resubmit this patch to netfilter-devel@vger.kernel.org.
Thanks.

^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2014-11-28 17:55 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2014-09-15 21:27 [PATCH 1/1] bridge: Fix NAT66ed IPv6 packets not being bridged correctly Bernhard Thaler
2014-09-15 21:40 ` David Miller
2014-10-03 11:21   ` Pablo Neira Ayuso
2014-11-27 19:26     ` Bernhard Thaler
2014-11-28 17:55       ` Pablo Neira Ayuso

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).