Module Name:    src
Committed By:   ozaki-r
Date:           Thu Apr 21 05:07:50 UTC 2016

Modified Files:
        src/sys/netinet6: nd6.c

Log Message:
Fix RTF_{REJECT,BLACKHOLE} behavior for IPv6 routes

We still need a nexthop route to reflect RTF_{REJECT,BLACKHOLE}.
In the future, we would do it w/o looking up a route.


To generate a diff of this commit:
cvs rdiff -u -r1.190 -r1.191 src/sys/netinet6/nd6.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/netinet6/nd6.c
diff -u src/sys/netinet6/nd6.c:1.190 src/sys/netinet6/nd6.c:1.191
--- src/sys/netinet6/nd6.c:1.190	Sun Apr 10 08:15:52 2016
+++ src/sys/netinet6/nd6.c	Thu Apr 21 05:07:50 2016
@@ -1,4 +1,4 @@
-/*	$NetBSD: nd6.c,v 1.190 2016/04/10 08:15:52 ozaki-r Exp $	*/
+/*	$NetBSD: nd6.c,v 1.191 2016/04/21 05:07:50 ozaki-r Exp $	*/
 /*	$KAME: nd6.c,v 1.279 2002/06/08 11:16:51 itojun Exp $	*/
 
 /*
@@ -31,7 +31,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.190 2016/04/10 08:15:52 ozaki-r Exp $");
+__KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.191 2016/04/21 05:07:50 ozaki-r Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_net_mpsafe.h"
@@ -2107,6 +2107,70 @@ nd6_slowtimo(void *ignored_arg)
 	mutex_exit(softnet_lock);
 }
 
+/*
+ * Next hop determination.  This routine was derived from ip_output.c.
+ */
+static int
+nd6_determine_nexthop(struct ifnet *ifp, const struct sockaddr_in6 *dst,
+    struct rtentry *rt0, struct rtentry **ret_rt, bool *sendpkt)
+{
+	struct rtentry *rt = rt0;
+	struct rtentry *gwrt = NULL;
+	struct sockaddr_in6 *gw6 = satosin6(rt->rt_gateway);
+
+	/*
+	 * We skip link-layer address resolution and NUD
+	 * if the gateway is not a neighbor from ND point
+	 * of view, regardless of the value of nd_ifinfo.flags.
+	 * The second condition is a bit tricky; we skip
+	 * if the gateway is our own address, which is
+	 * sometimes used to install a route to a p2p link.
+	 */
+	if (!nd6_is_addr_neighbor(gw6, ifp) ||
+	    in6ifa_ifpwithaddr(ifp, &gw6->sin6_addr)) {
+		/*
+		 * We allow this kind of tricky route only
+		 * when the outgoing interface is p2p.
+		 * XXX: we may need a more generic rule here.
+		 */
+		if ((ifp->if_flags & IFF_POINTOPOINT) == 0)
+			goto hostunreach;
+
+		*sendpkt = true;
+		return 0;
+	}
+
+	/* Try to use a cached nexthop route (gwroute) if exists */
+	gwrt = rt_get_gwroute(rt);
+	if (gwrt == NULL || (gwrt->rt_flags & RTF_UP) == 0) {
+		if (gwrt != NULL) {
+			rtfree(gwrt);
+		}
+		/* Look up a nexthop route */
+		gwrt = rtalloc1(rt->rt_gateway, 1);
+		rt_set_gwroute(rt, gwrt);
+		rt = gwrt;
+		if (rt == NULL)
+			goto hostunreach;
+		/* the "G" test below also prevents rt == rt0 */
+		if ((rt->rt_flags & RTF_GATEWAY) ||
+		    (rt->rt_ifp != ifp)) {
+			if (rt0->rt_gwroute != NULL)
+				rtfree(rt0->rt_gwroute);
+			rt0->rt_gwroute = NULL;
+			goto hostunreach;
+		}
+	}
+	*ret_rt = gwrt;
+	return 0;
+
+hostunreach:
+	if (gwrt != NULL)
+		rtfree(gwrt);
+
+	return EHOSTUNREACH;
+}
+
 int
 nd6_output(struct ifnet *ifp, struct ifnet *origifp, struct mbuf *m,
     const struct sockaddr_in6 *dst, struct rtentry *rt)
@@ -2115,6 +2179,7 @@ nd6_output(struct ifnet *ifp, struct ifn
 	struct llentry *ln = NULL;
 	int error = 0;
 	bool created = false;
+	struct rtentry *nexthop = NULL;
 
 	if (IN6_IS_ADDR_MULTICAST(&dst->sin6_addr))
 		goto sendpkt;
@@ -2129,6 +2194,19 @@ nd6_output(struct ifnet *ifp, struct ifn
 	 * or an anycast address(i.e. not a multicast).
 	 */
 
+	if (rt != NULL && (rt->rt_flags & RTF_GATEWAY) != 0) {
+		bool sendpkt = false;
+
+		/* Still need a nexthop to reflect RTF_{REJECT,BLACKHOLE} */
+		error = nd6_determine_nexthop(ifp, dst, rt, &nexthop, &sendpkt);
+		if (error != 0)
+			senderr(error);
+		if (nexthop != NULL)
+			rt = nexthop;
+		if (sendpkt)
+			goto sendpkt;
+	}
+
 	/* Look up the neighbor cache for the nexthop */
 	ln = nd6_lookup(&dst->sin6_addr, ifp, true);
 	if ((ln == NULL) && nd6_is_addr_neighbor(dst, ifp))  {
@@ -2262,6 +2340,9 @@ nd6_output(struct ifnet *ifp, struct ifn
 	if (m != NULL)
 		m_freem(m);
   exit:
+	if (nexthop != NULL)
+		rtfree(nexthop);
+
 	if (created)
 		nd6_gc_neighbors(LLTABLE6(ifp));
 

Reply via email to