Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src Add RO_MSGFILTER socket option to PF_ROUTE to filter out



details:   https://anonhg.NetBSD.org/src/rev/8387f5aad20f
branches:  trunk
changeset: 823062:8387f5aad20f
user:      roy <roy%NetBSD.org@localhost>
date:      Tue Apr 11 13:55:54 2017 +0000

description:
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.

diffstat:

 share/man/man4/route.4 |   21 ++++++++-
 sys/net/raw_cb.h       |    4 +-
 sys/net/raw_usrreq.c   |    7 ++-
 sys/net/route.h        |    7 ++-
 sys/net/rtsock.c       |  104 ++++++++++++++++++++++++++++++++++++++++++++++--
 5 files changed, 132 insertions(+), 11 deletions(-)

diffs (272 lines):

diff -r 73f7df55c1ce -r 8387f5aad20f share/man/man4/route.4
--- a/share/man/man4/route.4    Tue Apr 11 11:32:51 2017 +0000
+++ b/share/man/man4/route.4    Tue Apr 11 13:55:54 2017 +0000
@@ -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 @@
 .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
diff -r 73f7df55c1ce -r 8387f5aad20f sys/net/raw_cb.h
--- a/sys/net/raw_cb.h  Tue Apr 11 11:32:51 2017 +0000
+++ b/sys/net/raw_cb.h  Tue Apr 11 13:55:54 2017 +0000
@@ -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  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;
 };
 
diff -r 73f7df55c1ce -r 8387f5aad20f sys/net/raw_usrreq.c
--- a/sys/net/raw_usrreq.c      Tue Apr 11 11:32:51 2017 +0000
+++ b/sys/net/raw_usrreq.c      Tue Apr 11 13:55:54 2017 +0000
@@ -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 @@
                        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)
diff -r 73f7df55c1ce -r 8387f5aad20f sys/net/route.h
--- a/sys/net/route.h   Tue Apr 11 11:32:51 2017 +0000
+++ b/sys/net/route.h   Tue Apr 11 13:55:54 2017 +0000
@@ -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 @@
 #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 */
diff -r 73f7df55c1ce -r 8387f5aad20f sys/net/rtsock.c
--- a/sys/net/rtsock.c  Tue Apr 11 11:32:51 2017 +0000
+++ b/sys/net/rtsock.c  Tue Apr 11 13:55:54 2017 +0000
@@ -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 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 @@
 }
 
 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 @@
                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 @@
        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 @@
                .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,
        },



Home | Main Index | Thread Index | Old Index