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;

Reply via email to