lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite for Android: free password hash cracker in your pocket
[<prev] [next>] [thread-next>] [day] [month] [year] [list]
Date:	Mon,  6 Jun 2011 13:34:34 +0200
From:	Eric Leblond <eric@...it.org>
To:	netdev@...r.kernel.org
Cc:	Eric Leblond <eric@...it.org>
Subject: [RFC PATCH] ipv6: basic implementation of reverse path filtering

This patch provides a basic implementation of reverse path filtering
for IPv6. Functionnality can be activatedor desactivated through an
rp_filter entry similar to the IPv4 one.

The functionnality is disabled by default for backward compatibility
but should be enable on all IPv6 routers/firewalls for security reason.

This implementation is heavily based on the patch Denis Semmau proposed
in 2006.

Signed-off-by: Eric Leblond <eric@...it.org>
---
 include/linux/ipv6.h   |    2 ++
 include/linux/sysctl.h |    1 +
 net/ipv6/addrconf.c    |   10 ++++++++++
 net/ipv6/ip6_output.c  |   32 ++++++++++++++++++++++++++++++++
 4 files changed, 45 insertions(+), 0 deletions(-)

diff --git a/include/linux/ipv6.h b/include/linux/ipv6.h
index 0c99776..e61b88d 100644
--- a/include/linux/ipv6.h
+++ b/include/linux/ipv6.h
@@ -134,6 +134,7 @@ struct ipv6hdr {
  */
 struct ipv6_devconf {
 	__s32		forwarding;
+	__s32		rp_filter;
 	__s32		hop_limit;
 	__s32		mtu6;
 	__s32		accept_ra;
@@ -213,6 +214,7 @@ enum {
 	DEVCONF_DISABLE_IPV6,
 	DEVCONF_ACCEPT_DAD,
 	DEVCONF_FORCE_TLLAO,
+	DEVCONF_RP_FILTER,
 	DEVCONF_MAX
 };
 
diff --git a/include/linux/sysctl.h b/include/linux/sysctl.h
index 11684d9..bdcb7f8 100644
--- a/include/linux/sysctl.h
+++ b/include/linux/sysctl.h
@@ -568,6 +568,7 @@ enum {
 	NET_IPV6_ACCEPT_RA_RT_INFO_MAX_PLEN=22,
 	NET_IPV6_PROXY_NDP=23,
 	NET_IPV6_ACCEPT_SOURCE_ROUTE=25,
+	NET_IPV6_RP_FILTER=26,
 	__NET_IPV6_MAX
 };
 
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
index 498b927..ba1c574 100644
--- a/net/ipv6/addrconf.c
+++ b/net/ipv6/addrconf.c
@@ -196,6 +196,7 @@ static struct ipv6_devconf ipv6_devconf __read_mostly = {
 	.accept_source_route	= 0,	/* we do not accept RH0 by default. */
 	.disable_ipv6		= 0,
 	.accept_dad		= 1,
+	.rp_filter		= 0,
 };
 
 static struct ipv6_devconf ipv6_devconf_dflt __read_mostly = {
@@ -230,6 +231,7 @@ static struct ipv6_devconf ipv6_devconf_dflt __read_mostly = {
 	.accept_source_route	= 0,	/* we do not accept RH0 by default. */
 	.disable_ipv6		= 0,
 	.accept_dad		= 1,
+	.rp_filter		= 0,
 };
 
 /* IPv6 Wildcard Address and Loopback Address defined by RFC2553 */
@@ -3805,6 +3807,7 @@ static inline void ipv6_store_devconf(struct ipv6_devconf *cnf,
 	array[DEVCONF_DISABLE_IPV6] = cnf->disable_ipv6;
 	array[DEVCONF_ACCEPT_DAD] = cnf->accept_dad;
 	array[DEVCONF_FORCE_TLLAO] = cnf->force_tllao;
+	array[DEVCONF_RP_FILTER] = cnf->rp_filter;
 }
 
 static inline size_t inet6_ifla6_size(void)
@@ -4459,6 +4462,13 @@ static struct addrconf_sysctl_table
 			.proc_handler   = proc_dointvec
 		},
 		{
+			.procname       = "rp_filter",
+			.data           = &ipv6_devconf.rp_filter,
+			.maxlen         = sizeof(int),
+			.mode           = 0644,
+			.proc_handler   = proc_dointvec
+		},
+		{
 			/* sentinel */
 		}
 	},
diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c
index 9d4b165..c035494 100644
--- a/net/ipv6/ip6_output.c
+++ b/net/ipv6/ip6_output.c
@@ -374,6 +374,18 @@ static int ip6_forward_proxy_check(struct sk_buff *skb)
 	return 0;
 }
 
+static int rt6_validate_source(struct sk_buff *skb)
+{
+	struct rt6_info *rt;
+	struct ipv6hdr *hdr = ipv6_hdr(skb);
+	rt = rt6_lookup(dev_net(skb->dev), &hdr->saddr, NULL, 0, 0);
+	if (rt != NULL) {
+		if (rt->rt6i_idev->dev == skb->dev)
+			return 0;
+	}
+	return -1;
+}
+
 static inline int ip6_forward_finish(struct sk_buff *skb)
 {
 	return dst_output(skb);
@@ -384,6 +396,7 @@ int ip6_forward(struct sk_buff *skb)
 	struct dst_entry *dst = skb_dst(skb);
 	struct ipv6hdr *hdr = ipv6_hdr(skb);
 	struct inet6_skb_parm *opt = IP6CB(skb);
+	struct inet6_dev *idev = NULL;
 	struct net *net = dev_net(dst->dev);
 	u32 mtu;
 
@@ -401,6 +414,25 @@ int ip6_forward(struct sk_buff *skb)
 	if (skb->pkt_type != PACKET_HOST)
 		goto drop;
 
+	idev = in6_dev_get(skb->dev);
+	if (!idev) {
+		printk(KERN_WARNING "idev error for rp_filter\n");
+		goto error;
+	}
+
+	if (net->ipv6.devconf_all->rp_filter & idev->cnf.rp_filter) {
+		if (rt6_validate_source(skb) < 0) {
+			printk(KERN_WARNING
+			       "rp_filter: packet refused on %s, invalid src %pI6 (dst: %pI6)",
+			       skb->dev->name,
+			       &hdr->saddr,
+			       &hdr->daddr
+			      );
+			goto drop;
+		}
+
+	}
+
 	skb_forward_csum(skb);
 
 	/*
-- 
1.7.5.3

--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ