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