--- /dev/null
+From davem@davemloft.net Wed Apr 25 21:58:14 2007
+From: David Miller <davem@davemloft.net>
+Date: Wed, 25 Apr 2007 21:56:57 -0700 (PDT)
+Subject: IPV6: Disallow RH0 by default.
+To: gregkh@suse.de
+Cc: greg@kroah.com
+Message-ID: <20070425.215657.45874324.davem@davemloft.net>
+
+From: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
+
+[IPV6]: Disallow RH0 by default.
+
+A security issue is emerging. Disallow Routing Header Type 0 by default
+as we have been doing for IPv4.
+Note: We allow RH2 by default because it is harmless.
+
+Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ Documentation/networking/ip-sysctl.txt | 9 +++++++
+ include/linux/ipv6.h | 3 ++
+ include/linux/sysctl.h | 1
+ net/ipv6/addrconf.c | 11 +++++++++
+ net/ipv6/exthdrs.c | 40 ++++++++++++++++++++++++++++-----
+ 5 files changed, 58 insertions(+), 6 deletions(-)
+
+--- a/Documentation/networking/ip-sysctl.txt
++++ b/Documentation/networking/ip-sysctl.txt
+@@ -825,6 +825,15 @@ accept_redirects - BOOLEAN
+ Functional default: enabled if local forwarding is disabled.
+ disabled if local forwarding is enabled.
+
++accept_source_route - INTEGER
++ Accept source routing (routing extension header).
++
++ > 0: Accept routing header.
++ = 0: Accept only routing header type 2.
++ < 0: Do not accept routing header.
++
++ Default: 0
++
+ autoconf - BOOLEAN
+ Autoconfigure addresses using Prefix Information in Router
+ Advertisements.
+--- a/include/linux/ipv6.h
++++ b/include/linux/ipv6.h
+@@ -177,6 +177,7 @@ struct ipv6_devconf {
+ #endif
+ #endif
+ __s32 proxy_ndp;
++ __s32 accept_source_route;
+ void *sysctl;
+ };
+
+@@ -205,6 +206,8 @@ enum {
+ DEVCONF_RTR_PROBE_INTERVAL,
+ DEVCONF_ACCEPT_RA_RT_INFO_MAX_PLEN,
+ DEVCONF_PROXY_NDP,
++ __DEVCONF_OPTIMISTIC_DAD,
++ DEVCONF_ACCEPT_SOURCE_ROUTE,
+ DEVCONF_MAX
+ };
+
+--- a/include/linux/sysctl.h
++++ b/include/linux/sysctl.h
+@@ -570,6 +570,7 @@ enum {
+ NET_IPV6_RTR_PROBE_INTERVAL=21,
+ NET_IPV6_ACCEPT_RA_RT_INFO_MAX_PLEN=22,
+ NET_IPV6_PROXY_NDP=23,
++ NET_IPV6_ACCEPT_SOURCE_ROUTE=25,
+ __NET_IPV6_MAX
+ };
+
+--- a/net/ipv6/addrconf.c
++++ b/net/ipv6/addrconf.c
+@@ -173,6 +173,7 @@ struct ipv6_devconf ipv6_devconf __read_
+ #endif
+ #endif
+ .proxy_ndp = 0,
++ .accept_source_route = 0, /* we do not accept RH0 by default. */
+ };
+
+ static struct ipv6_devconf ipv6_devconf_dflt __read_mostly = {
+@@ -204,6 +205,7 @@ static struct ipv6_devconf ipv6_devconf_
+ #endif
+ #endif
+ .proxy_ndp = 0,
++ .accept_source_route = 0, /* we do not accept RH0 by default. */
+ };
+
+ /* IPv6 Wildcard Address and Loopback Address defined by RFC2553 */
+@@ -3400,6 +3402,7 @@ static void inline ipv6_store_devconf(st
+ #endif
+ #endif
+ array[DEVCONF_PROXY_NDP] = cnf->proxy_ndp;
++ array[DEVCONF_ACCEPT_SOURCE_ROUTE] = cnf->accept_source_route;
+ }
+
+ static inline size_t inet6_if_nlmsg_size(void)
+@@ -3920,6 +3923,14 @@ static struct addrconf_sysctl_table
+ .proc_handler = &proc_dointvec,
+ },
+ {
++ .ctl_name = NET_IPV6_ACCEPT_SOURCE_ROUTE,
++ .procname = "accept_source_route",
++ .data = &ipv6_devconf.accept_source_route,
++ .maxlen = sizeof(int),
++ .mode = 0644,
++ .proc_handler = &proc_dointvec,
++ },
++ {
+ .ctl_name = 0, /* sentinel */
+ }
+ },
+--- a/net/ipv6/exthdrs.c
++++ b/net/ipv6/exthdrs.c
+@@ -363,10 +363,27 @@ static int ipv6_rthdr_rcv(struct sk_buff
+ struct inet6_skb_parm *opt = IP6CB(skb);
+ struct in6_addr *addr = NULL;
+ struct in6_addr daddr;
++ struct inet6_dev *idev;
+ int n, i;
+-
+ struct ipv6_rt_hdr *hdr;
+ struct rt0_hdr *rthdr;
++ int accept_source_route = ipv6_devconf.accept_source_route;
++
++ if (accept_source_route < 0 ||
++ ((idev = in6_dev_get(skb->dev)) == NULL)) {
++ kfree_skb(skb);
++ return -1;
++ }
++ if (idev->cnf.accept_source_route < 0) {
++ in6_dev_put(idev);
++ kfree_skb(skb);
++ return -1;
++ }
++
++ if (accept_source_route > idev->cnf.accept_source_route)
++ accept_source_route = idev->cnf.accept_source_route;
++
++ in6_dev_put(idev);
+
+ if (!pskb_may_pull(skb, (skb->h.raw-skb->data)+8) ||
+ !pskb_may_pull(skb, (skb->h.raw-skb->data)+((skb->h.raw[1]+1)<<3))) {
+@@ -378,6 +395,22 @@ static int ipv6_rthdr_rcv(struct sk_buff
+
+ hdr = (struct ipv6_rt_hdr *) skb->h.raw;
+
++ switch (hdr->type) {
++#ifdef CONFIG_IPV6_MIP6
++ break;
++#endif
++ case IPV6_SRCRT_TYPE_0:
++ if (accept_source_route > 0)
++ break;
++ kfree_skb(skb);
++ return -1;
++ default:
++ IP6_INC_STATS_BH(ip6_dst_idev(skb->dst),
++ IPSTATS_MIB_INHDRERRORS);
++ icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, (&hdr->type) - skb->nh.raw);
++ return -1;
++ }
++
+ if (ipv6_addr_is_multicast(&skb->nh.ipv6h->daddr) ||
+ skb->pkt_type != PACKET_HOST) {
+ IP6_INC_STATS_BH(ip6_dst_idev(skb->dst),
+@@ -435,11 +468,6 @@ looped_back:
+ }
+ break;
+ #endif
+- default:
+- IP6_INC_STATS_BH(ip6_dst_idev(skb->dst),
+- IPSTATS_MIB_INHDRERRORS);
+- icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, (&hdr->type) - skb->nh.raw);
+- return -1;
+ }
+
+ /*