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,
},