Source-Changes-HG archive

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

[src/trunk]: src/sys/net route(4): add RO_MISSFILTER socket option



details:   https://anonhg.NetBSD.org/src/rev/35931e4577de
branches:  trunk
changeset: 969131:35931e4577de
user:      roy <roy%NetBSD.org@localhost>
date:      Sat Feb 08 14:17:30 2020 +0000

description:
route(4): add RO_MISSFILTER socket option

This allows filtering of specific RTM_MISS destination sockaddrs.

diffstat:

 share/man/man4/route.4  |  33 ++++++++++++++++++++-
 sys/net/route.h         |   5 ++-
 sys/net/rtsock_shared.c |  74 +++++++++++++++++++++++++++++++++++++++++++++---
 3 files changed, 104 insertions(+), 8 deletions(-)

diffs (213 lines):

diff -r a631ec74b1b2 -r 35931e4577de share/man/man4/route.4
--- a/share/man/man4/route.4    Sat Feb 08 13:44:35 2020 +0000
+++ b/share/man/man4/route.4    Sat Feb 08 14:17:30 2020 +0000
@@ -1,4 +1,4 @@
-.\"    $NetBSD: route.4,v 1.32 2018/07/01 22:27:43 christos Exp $
+.\"    $NetBSD: route.4,v 1.33 2020/02/08 14:17:30 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 July 11, 2018
+.Dd February 4, 2020
 .Dt ROUTE 4
 .Os
 .Sh NAME
@@ -191,6 +191,35 @@
        err(1, "setsockopt(RO_MSGFILTER)");
 .Ed
 .Pp
+A process can specify which RTM_MISS destination addresses it's interested in
+by passing an array of struct sockaddr to the
+.Xr setsockopt 2
+call with the
+.Dv RO_MISSFILTER
+option at the
+.Dv PF_ROUTE
+level.
+For example, to only get RTM_MISS messages for specific destinations:
+.Bd -literal -offset indent
+char buf[1024] = { '\\0' }, *cp = buf;
+struct sockaddr_in sin = {
+       .sin_family = AF_INET,
+       .sin_len = sizeof(sin),
+};
+
+inet_aton("192.168.0.1", &sin.sin_addr);
+memcpy(cp, &sin, sin.sin_len);
+cp += RT_ROUNDUP(sin.sin_len);
+
+inet_aton("192.168.0.2", &sin.sin_addr);
+memcpy(cp, &sin, sin.sin_len);
+cp += RT_ROUNDUP(sin.sin_len);
+
+if (setsockopt(routefd, PF_ROUTE, RO_MISSFILTER,
+    &sin, (socklen_t)(cp - buf)) == -1)
+       err(1, "setsockopt(RO_MISSFILTER)");
+.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 a631ec74b1b2 -r 35931e4577de sys/net/route.h
--- a/sys/net/route.h   Sat Feb 08 13:44:35 2020 +0000
+++ b/sys/net/route.h   Sat Feb 08 14:17:30 2020 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: route.h,v 1.125 2019/09/19 04:08:29 ozaki-r Exp $      */
+/*     $NetBSD: route.h,v 1.126 2020/02/08 14:17:30 roy Exp $  */
 
 /*
  * Copyright (c) 1980, 1986, 1993
@@ -270,6 +270,9 @@
  * setsockopt defines used for the filtering.
  */
 #define        RO_MSGFILTER    1       /* array of which rtm_type to send to client */
+#define        RO_MISSFILTER   2       /* array of sockaddrs to match miss dst */
+
+#define        RO_FILTSA_MAX   30      /* maximum number of sockaddrs per filter */
 
 #define RTV_MTU                0x1     /* init or lock _mtu */
 #define RTV_HOPCOUNT   0x2     /* init or lock _hopcount */
diff -r a631ec74b1b2 -r 35931e4577de sys/net/rtsock_shared.c
--- a/sys/net/rtsock_shared.c   Sat Feb 08 13:44:35 2020 +0000
+++ b/sys/net/rtsock_shared.c   Sat Feb 08 14:17:30 2020 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: rtsock_shared.c,v 1.12 2020/01/29 04:35:13 thorpej Exp $       */
+/*     $NetBSD: rtsock_shared.c,v 1.13 2020/02/08 14:17:30 roy Exp $   */
 
 /*
  * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
@@ -61,7 +61,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: rtsock_shared.c,v 1.12 2020/01/29 04:35:13 thorpej Exp $");
+__KERNEL_RCSID(0, "$NetBSD: rtsock_shared.c,v 1.13 2020/02/08 14:17:30 roy Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_inet.h"
@@ -169,6 +169,8 @@
        struct rawcb    rocb_rcb;
        unsigned int    rocb_msgfilter;
 #define        RTMSGFILTER(m)  (1U << (m))
+       char            *rocb_missfilter;
+       size_t          rocb_missfilterlen;
 };
 #define sotoroutecb(so)        ((struct routecb *)(so)->so_pcb)
 
@@ -218,7 +220,7 @@
                return ENOPROTOOPT;
 
        /* If no filter set, just return. */
-       if (rop->rocb_msgfilter == 0)
+       if (rop->rocb_msgfilter == 0 && rop->rocb_missfilterlen == 0)
                return 0;
 
        /* Ensure we can access rtm_type */
@@ -230,9 +232,27 @@
        if (rtm->rtm_type >= sizeof(rop->rocb_msgfilter) * CHAR_BIT)
                return EINVAL;
        /* If the rtm type is filtered out, return a positive. */
-       if (!(rop->rocb_msgfilter & RTMSGFILTER(rtm->rtm_type)))
+       if (rop->rocb_msgfilter != 0 &&
+           !(rop->rocb_msgfilter & RTMSGFILTER(rtm->rtm_type)))
                return EEXIST;
 
+       if (rop->rocb_missfilterlen != 0 && rtm->rtm_type == RTM_MISS) {
+               __CTASSERT(RTA_DST == 1);
+               struct sockaddr *sa, *dst = (struct sockaddr *)(rtm + 1);
+               char *cp = rop->rocb_missfilter;
+               char *ep = cp + rop->rocb_missfilterlen;
+
+               while (cp < ep) {
+                       sa = (struct sockaddr *)cp;
+                       if (sa->sa_len == dst->sa_len &&
+                           memcmp(sa, dst, sa->sa_len) == 0)
+                               break;
+                       cp += RT_XROUNDUP(sa->sa_len);
+               }
+               if (cp == ep)
+                       return EEXIST;
+       }
+
        /* Passed the filter. */
        return 0;
 }
@@ -291,12 +311,15 @@
 COMPATNAME(route_detach)(struct socket *so)
 {
        struct rawcb *rp = sotorawcb(so);
+       struct routecb *rop = (struct routecb *)rp;
        int s;
 
        KASSERT(rp != NULL);
        KASSERT(solocked(so));
 
        s = splsoftnet();
+       if (rop->rocb_missfilterlen != 0)
+               kmem_free(rop->rocb_missfilter, rop->rocb_missfilterlen);
        rt_adjustcount(rp->rcb_proto.sp_protocol, -1);
        raw_detach(so);
        splx(s);
@@ -980,9 +1003,10 @@
 {
        struct routecb *rop = sotoroutecb(so);
        int error = 0;
-       unsigned char *rtm_type;
+       unsigned char *rtm_type, *cp, *ep;
        size_t len;
        unsigned int msgfilter;
+       struct sockaddr *sa;
 
        KASSERT(solocked(so));
 
@@ -1007,6 +1031,46 @@
                        if (error == 0)
                                rop->rocb_msgfilter = msgfilter;
                        break;
+               case RO_MISSFILTER:
+                       /* Validate the data */
+                       len = 0;
+                       cp = sopt->sopt_data;
+                       ep = cp + sopt->sopt_size;
+                       while (cp < ep) {
+                               if (ep - cp <
+                                   offsetof(struct sockaddr, sa_len) +
+                                   sizeof(sa->sa_len))
+                                       break;
+                               if (++len > RO_FILTSA_MAX) {
+                                       error = ENOBUFS;
+                                       break;
+                               }
+                               sa = (struct sockaddr *)cp;
+                               cp += RT_XROUNDUP(sa->sa_len);
+                       }
+                       if (cp != ep) {
+                               if (error == 0)
+                                       error = EINVAL;
+                               break;
+                       }
+                       if (rop->rocb_missfilterlen != 0)
+                               kmem_free(rop->rocb_missfilter,
+                                   rop->rocb_missfilterlen);
+                       if (sopt->sopt_size != 0) {
+                               rop->rocb_missfilter =
+                                   kmem_alloc(sopt->sopt_size, KM_SLEEP);
+                               if (rop->rocb_missfilter == NULL) {
+                                       rop->rocb_missfilterlen = 0;
+                                       error = ENOBUFS;
+                                       break;
+                               }
+                       } else
+                               rop->rocb_missfilter = NULL;
+                       rop->rocb_missfilterlen = sopt->sopt_size;
+                       if (rop->rocb_missfilterlen != 0)
+                               memcpy(rop->rocb_missfilter, sopt->sopt_data,
+                                   rop->rocb_missfilterlen);
+                       break;
                default:
                        error = ENOPROTOOPT;
                        break;



Home | Main Index | Thread Index | Old Index