Module Name:    src
Committed By:   roy
Date:           Tue Apr 11 13:55:55 UTC 2017

Modified Files:
        src/share/man/man4: route.4
        src/sys/net: raw_cb.h raw_usrreq.c route.h rtsock.c

Log Message:
Add RO_MSGFILTER socket option to PF_ROUTE to filter out
un-wanted route(4) messages.

Inspired by the ROUTE_MSGFILTER equivalent in OpenBSD,
but with an API which allows the full range of potential message types.


To generate a diff of this commit:
cvs rdiff -u -r1.28 -r1.29 src/share/man/man4/route.4
cvs rdiff -u -r1.26 -r1.27 src/sys/net/raw_cb.h
cvs rdiff -u -r1.55 -r1.56 src/sys/net/raw_usrreq.c
cvs rdiff -u -r1.111 -r1.112 src/sys/net/route.h
cvs rdiff -u -r1.211 -r1.212 src/sys/net/rtsock.c

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

Modified files:

Index: src/share/man/man4/route.4
diff -u src/share/man/man4/route.4:1.28 src/share/man/man4/route.4:1.29
--- src/share/man/man4/route.4:1.28	Wed Sep 21 10:50:23 2016
+++ src/share/man/man4/route.4	Tue Apr 11 13:55:54 2017
@@ -1,4 +1,4 @@
-.\"	$NetBSD: route.4,v 1.28 2016/09/21 10:50:23 roy Exp $
+.\"	$NetBSD: route.4,v 1.29 2017/04/11 13:55:54 roy Exp $
 .\"
 .\" Copyright (c) 1990, 1991, 1993
 .\"	The Regents of the University of California.  All rights reserved.
@@ -29,7 +29,7 @@
 .\"
 .\"     @(#)route.4	8.6 (Berkeley) 4/19/94
 .\"
-.Dd September 15, 2016
+.Dd March 5, 2017
 .Dt ROUTE 4
 .Os
 .Sh NAME
@@ -174,6 +174,23 @@ by doing a
 .Xr shutdown 2
 system call for further input.
 .Pp
+A process can specify which route message types it's interested in by passing
+an array of route messsage types to the
+.Xr setsockopt 2
+call with the
+.Dv RO_MSGFILTER
+option at the
+.Dv PF_ROUTE
+level.
+For example, to only get specific messages:
+.Bd -literal -offset indent
+unsigned char rtfilter[] = { RTM_IFINFO, RTM_IFANNOUNCE };
+
+if (setsockopt(routefd, PF_ROUTE, RO_MSGFILTER,
+    &rtfilter, sizeof(rtfilter)) == -1)
+	err(1, "setsockopt(RO_MSGFILTER)");
+.Ed
+.Pp
 If a route is in use when it is deleted,
 the routing entry will be marked down and removed from the routing table,
 but the resources associated with it will not

Index: src/sys/net/raw_cb.h
diff -u src/sys/net/raw_cb.h:1.26 src/sys/net/raw_cb.h:1.27
--- src/sys/net/raw_cb.h:1.26	Wed Jan 20 21:43:59 2016
+++ src/sys/net/raw_cb.h	Tue Apr 11 13:55:54 2017
@@ -1,4 +1,4 @@
-/*	$NetBSD: raw_cb.h,v 1.26 2016/01/20 21:43:59 riastradh Exp $	*/
+/*	$NetBSD: raw_cb.h,v 1.27 2017/04/11 13:55:54 roy Exp $	*/
 
 /*
  * Copyright (c) 1980, 1986, 1993
@@ -46,6 +46,8 @@ struct rawcb {
 	struct	sockaddr *rcb_faddr;	/* destination address */
 	struct	sockaddr *rcb_laddr;	/* socket's address */
 	struct	sockproto rcb_proto;	/* protocol family, protocol */
+	int	(*rcb_filter)(struct mbuf *, struct sockproto *,
+		              struct rawcb *);
 	size_t	rcb_len;
 };
 

Index: src/sys/net/raw_usrreq.c
diff -u src/sys/net/raw_usrreq.c:1.55 src/sys/net/raw_usrreq.c:1.56
--- src/sys/net/raw_usrreq.c:1.55	Wed Jan 20 21:43:59 2016
+++ src/sys/net/raw_usrreq.c	Tue Apr 11 13:55:54 2017
@@ -1,4 +1,4 @@
-/*	$NetBSD: raw_usrreq.c,v 1.55 2016/01/20 21:43:59 riastradh Exp $	*/
+/*	$NetBSD: raw_usrreq.c,v 1.56 2017/04/11 13:55:54 roy Exp $	*/
 
 /*
  * Copyright (c) 1980, 1986, 1993
@@ -36,7 +36,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: raw_usrreq.c,v 1.55 2016/01/20 21:43:59 riastradh Exp $");
+__KERNEL_RCSID(0, "$NetBSD: raw_usrreq.c,v 1.56 2017/04/11 13:55:54 roy Exp $");
 
 #include <sys/param.h>
 #include <sys/mbuf.h>
@@ -107,6 +107,9 @@ raw_input(struct mbuf *m0, ...)
 			continue;
 		if (rp->rcb_faddr && !equal(rp->rcb_faddr, src))
 			continue;
+		/* Run any filtering that may have been installed. */
+		if (rp->rcb_filter != NULL && rp->rcb_filter(m, proto, rp) != 0)
+			continue;
 		if (last != NULL) {
 			struct mbuf *n;
 			if ((n = m_copy(m, 0, M_COPYALL)) == NULL)

Index: src/sys/net/route.h
diff -u src/sys/net/route.h:1.111 src/sys/net/route.h:1.112
--- src/sys/net/route.h:1.111	Mon Dec 19 11:17:00 2016
+++ src/sys/net/route.h	Tue Apr 11 13:55:54 2017
@@ -1,4 +1,4 @@
-/*	$NetBSD: route.h,v 1.111 2016/12/19 11:17:00 roy Exp $	*/
+/*	$NetBSD: route.h,v 1.112 2017/04/11 13:55:54 roy Exp $	*/
 
 /*
  * Copyright (c) 1980, 1986, 1993
@@ -250,6 +250,11 @@ struct rt_msghdr {
 #define RTM_DELADDR	0x17	/* address being removed from iface */
 #define RTM_CHGADDR	0x18	/* address properties changed */
 
+/*
+ * setsockopt defines used for the filtering.
+ */
+#define	RO_MSGFILTER	1	/* array of which rtm_type to send to client */
+
 #define RTV_MTU		0x1	/* init or lock _mtu */
 #define RTV_HOPCOUNT	0x2	/* init or lock _hopcount */
 #define RTV_EXPIRE	0x4	/* init or lock _expire */

Index: src/sys/net/rtsock.c
diff -u src/sys/net/rtsock.c:1.211 src/sys/net/rtsock.c:1.212
--- src/sys/net/rtsock.c:1.211	Fri Mar 24 03:45:02 2017
+++ src/sys/net/rtsock.c	Tue Apr 11 13:55:55 2017
@@ -1,4 +1,4 @@
-/*	$NetBSD: rtsock.c,v 1.211 2017/03/24 03:45:02 ozaki-r Exp $	*/
+/*	$NetBSD: rtsock.c,v 1.212 2017/04/11 13:55:55 roy Exp $	*/
 
 /*
  * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
@@ -61,7 +61,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: rtsock.c,v 1.211 2017/03/24 03:45:02 ozaki-r Exp $");
+__KERNEL_RCSID(0, "$NetBSD: rtsock.c,v 1.212 2017/04/11 13:55:55 roy Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_inet.h"
@@ -177,6 +177,13 @@ static void rt_adjustcount(int, int);
 
 static const struct protosw COMPATNAME(route_protosw)[];
 
+struct routecb {
+	struct rawcb	rocb_rcb;
+	unsigned int	rocb_msgfilter;
+#define	RTMSGFILTER(m)	(1U << (m))
+};
+#define sotoroutecb(so)	((struct routecb *)(so)->so_pcb)
+
 static void
 rt_adjustcount(int af, int cnt)
 {
@@ -200,14 +207,49 @@ rt_adjustcount(int af, int cnt)
 }
 
 static int
+COMPATNAME(route_filter)(struct mbuf *m, struct sockproto *proto,
+    struct rawcb *rp)
+{
+	struct routecb *rop = (struct routecb *)rp;
+	struct rt_xmsghdr *rtm;
+
+	KASSERT(m != NULL);
+	KASSERT(proto != NULL);
+	KASSERT(rp != NULL);
+
+	/* Wrong family for this socket. */
+	if (proto->sp_family != PF_ROUTE)
+		return ENOPROTOOPT;
+
+	/* If no filter set, just return. */
+	if (rop->rocb_msgfilter == 0)
+		return 0;
+
+	/* Ensure we can access rtm_type */
+	if (m->m_len <
+	    offsetof(struct rt_xmsghdr, rtm_type) + sizeof(rtm->rtm_type))
+		return EINVAL;
+
+	rtm = mtod(m, struct rt_xmsghdr *);
+	/* If the rtm type is filtered out, return a positive. */
+	if (!(rop->rocb_msgfilter & RTMSGFILTER(rtm->rtm_type)))
+		return EEXIST;
+
+	/* Passed the filter. */
+	return 0;
+}
+
+static int
 COMPATNAME(route_attach)(struct socket *so, int proto)
 {
 	struct rawcb *rp;
+	struct routecb *rop;
 	int s, error;
 
 	KASSERT(sotorawcb(so) == NULL);
-	rp = kmem_zalloc(sizeof(*rp), KM_SLEEP);
-	rp->rcb_len = sizeof(*rp);
+	rop = kmem_zalloc(sizeof(*rop), KM_SLEEP);
+	rp = &rop->rocb_rcb;
+	rp->rcb_len = sizeof(*rop);
 	so->so_pcb = rp;
 
 	s = splsoftnet();
@@ -215,11 +257,12 @@ COMPATNAME(route_attach)(struct socket *
 		rt_adjustcount(rp->rcb_proto.sp_protocol, 1);
 		rp->rcb_laddr = &COMPATNAME(route_info).ri_src;
 		rp->rcb_faddr = &COMPATNAME(route_info).ri_dst;
+		rp->rcb_filter = COMPATNAME(route_filter);
 	}
 	splx(s);
 
 	if (error) {
-		kmem_free(rp, sizeof(*rp));
+		kmem_free(rop, sizeof(*rop));
 		so->so_pcb = NULL;
 		return error;
 	}
@@ -981,6 +1024,56 @@ out:
 	return error;
 }
 
+static int
+route_ctloutput(int op, struct socket *so, struct sockopt *sopt)
+{
+	struct routecb *rop = sotoroutecb(so);
+	int error = 0;
+	unsigned char *rtm_type;
+	size_t len;
+	unsigned int msgfilter;
+
+	KASSERT(solocked(so));
+
+	if (sopt->sopt_level != AF_ROUTE) {
+		error = ENOPROTOOPT;
+	} else switch (op) {
+	case PRCO_SETOPT:
+		switch (sopt->sopt_name) {
+		case RO_MSGFILTER:
+			msgfilter = 0;
+			for (rtm_type = sopt->sopt_data, len = sopt->sopt_size;
+			     len != 0;
+			     rtm_type++, len -= sizeof(*rtm_type))
+			{
+				/* Guard against overflowing our storage. */
+				if (*rtm_type >= sizeof(msgfilter) * CHAR_BIT) {
+					error = EOVERFLOW;
+					break;
+				}
+				msgfilter |= RTMSGFILTER(*rtm_type);
+			}
+			if (error == 0)
+				rop->rocb_msgfilter = msgfilter;
+			break;
+		default:
+			error = ENOPROTOOPT;
+			break;
+		}
+		break;
+	case PRCO_GETOPT:
+		switch (sopt->sopt_name) {
+		case RO_MSGFILTER:
+			error = ENOTSUP;
+			break;
+		default:
+			error = ENOPROTOOPT;
+			break;
+		}
+	}
+	return error;
+}
+
 static void
 rt_setmetrics(int which, const struct rt_xmsghdr *in, struct rtentry *out)
 {
@@ -1946,6 +2039,7 @@ static const struct protosw COMPATNAME(r
 		.pr_flags = PR_ATOMIC|PR_ADDR,
 		.pr_input = raw_input,
 		.pr_ctlinput = raw_ctlinput,
+		.pr_ctloutput = route_ctloutput,
 		.pr_usrreqs = &route_usrreqs,
 		.pr_init = raw_init,
 	},

Reply via email to