Module Name: src Committed By: roy Date: Sat Feb 8 14:17:30 UTC 2020
Modified Files: src/share/man/man4: route.4 src/sys/net: route.h rtsock_shared.c Log Message: route(4): add RO_MISSFILTER socket option This allows filtering of specific RTM_MISS destination sockaddrs. To generate a diff of this commit: cvs rdiff -u -r1.32 -r1.33 src/share/man/man4/route.4 cvs rdiff -u -r1.125 -r1.126 src/sys/net/route.h cvs rdiff -u -r1.12 -r1.13 src/sys/net/rtsock_shared.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.32 src/share/man/man4/route.4:1.33 --- src/share/man/man4/route.4:1.32 Sun Jul 1 22:27:43 2018 +++ src/share/man/man4/route.4 Sat Feb 8 14:17:30 2020 @@ -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 @@ if (setsockopt(routefd, PF_ROUTE, RO_MSG 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 Index: src/sys/net/route.h diff -u src/sys/net/route.h:1.125 src/sys/net/route.h:1.126 --- src/sys/net/route.h:1.125 Thu Sep 19 04:08:29 2019 +++ src/sys/net/route.h Sat Feb 8 14:17:30 2020 @@ -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 @@ struct rt_msghdr { * 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 */ Index: src/sys/net/rtsock_shared.c diff -u src/sys/net/rtsock_shared.c:1.12 src/sys/net/rtsock_shared.c:1.13 --- src/sys/net/rtsock_shared.c:1.12 Wed Jan 29 04:35:13 2020 +++ src/sys/net/rtsock_shared.c Sat Feb 8 14:17:30 2020 @@ -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 routecb { 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 @@ COMPATNAME(route_filter)(struct mbuf *m, 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 @@ COMPATNAME(route_filter)(struct mbuf *m, 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 @@ static void 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 @@ route_ctloutput(int op, struct socket *s { 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 @@ route_ctloutput(int op, struct socket *s 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;