git: d50fc4ba54e6 - main - rpcbind: run netlink(4) service

From: Gleb Smirnoff <glebius_at_FreeBSD.org>
Date: Sat, 01 Feb 2025 09:02:12 UTC
The branch main has been updated by glebius:

URL: https://cgit.FreeBSD.org/src/commit/?id=d50fc4ba54e6c95fcff9acf1a137fa037294ffbf

commit d50fc4ba54e6c95fcff9acf1a137fa037294ffbf
Author:     Gleb Smirnoff <glebius@FreeBSD.org>
AuthorDate: 2025-02-01 01:02:21 +0000
Commit:     Gleb Smirnoff <glebius@FreeBSD.org>
CommitDate: 2025-02-01 09:00:26 +0000

    rpcbind: run netlink(4) service
    
    To register RPC bindings coming from the kernel.  At the moment, we expect
    such bindings only from the kernel NLM service.
    
    Reviewed by:            rmacklem
    Differential Revision:  https://reviews.freebsd.org/D48556
---
 usr.sbin/rpcbind/rpcbind.c  | 69 +++++++++++++++++++++++++++------------------
 usr.sbin/rpcbind/security.c |  1 +
 2 files changed, 43 insertions(+), 27 deletions(-)

diff --git a/usr.sbin/rpcbind/rpcbind.c b/usr.sbin/rpcbind/rpcbind.c
index a836afd24009..1397a0222396 100644
--- a/usr.sbin/rpcbind/rpcbind.c
+++ b/usr.sbin/rpcbind/rpcbind.c
@@ -54,8 +54,10 @@
 #include <netinet/in.h>
 #endif
 #include <arpa/inet.h>
+#include <assert.h>
 #include <fcntl.h>
 #include <netdb.h>
+#include <stdbool.h>
 #include <stdio.h>
 #include <netconfig.h>
 #include <stdlib.h>
@@ -111,8 +113,20 @@ char *tcp_uaddr;	/* Universal TCP address */
 #endif
 static char servname[] = "rpcbind";
 static char superuser[] = "superuser";
+static char nlname[] = "netlink";
 
-int main(int, char *[]);
+static struct netconfig netlink_nconf = {
+	.nc_netid = nlname,
+	.nc_semantics = NC_TPI_CLTS,
+};
+
+static struct t_bind netlink_taddr = {
+	.addr = {
+		.maxlen = sizeof(nlname),
+		.len = sizeof(nlname),
+		.buf = nlname,
+	},
+};
 
 static int init_transport(struct netconfig *);
 static void rbllist_add(rpcprog_t, rpcvers_t, struct netconfig *,
@@ -188,6 +202,8 @@ main(int argc, char *argv[])
 	}
 	endnetconfig(nc_handle);
 
+	init_transport(&netlink_nconf);
+
 	/*
 	 * Allocate pipe fd to wake main thread from signal handler in non-racy
 	 * way.
@@ -256,11 +272,11 @@ main(int argc, char *argv[])
 static int
 init_transport(struct netconfig *nconf)
 {
-	int fd;
+	int fd = -1;
 	struct t_bind taddr;
 	struct addrinfo hints, *res = NULL;
 	struct __rpc_sockinfo si;
-	SVCXPRT	*my_xprt;
+	SVCXPRT	*my_xprt = NULL;
 	int status;	/* bound checking ? */
 	int aicode;
 	int addrlen;
@@ -270,6 +286,11 @@ init_transport(struct netconfig *nconf)
 	u_int32_t host_addr[4];  /* IPv4 or IPv6 */
 	struct sockaddr_un sun;
 	mode_t oldmask;
+	bool local, netlink;
+
+	local = strcmp(nconf->nc_netid, "local") == 0 ||
+	    strcmp(nconf->nc_netid, "unix") == 0;
+	netlink = strcmp(nconf->nc_netid, "netlink") == 0;
 
 	if ((nconf->nc_semantics != NC_TPI_CLTS) &&
 	    (nconf->nc_semantics != NC_TPI_COTS) &&
@@ -291,8 +312,7 @@ init_transport(struct netconfig *nconf)
 	/*
 	 * XXX - using RPC library internal functions.
 	 */
-	if ((strcmp(nconf->nc_netid, "local") == 0) ||
-	    (strcmp(nconf->nc_netid, "unix") == 0)) {
+	if (local) {
 	    /* 
 	     * For other transports we call this later, for each socket we
 	     * like to bind.
@@ -313,8 +333,7 @@ init_transport(struct netconfig *nconf)
 	    return (1);
 	}
 
-	if ((strcmp(nconf->nc_netid, "local") == 0) ||
-	    (strcmp(nconf->nc_netid, "unix") == 0)) {
+	if (local) {
 	    memset(&sun, 0, sizeof sun);
 	    sun.sun_family = AF_LOCAL;
 	    unlink(_PATH_RPCBINDSOCK);
@@ -322,7 +341,7 @@ init_transport(struct netconfig *nconf)
 	    sun.sun_len = SUN_LEN(&sun);
 	    addrlen = sizeof (struct sockaddr_un);
 	    sa = (struct sockaddr *)&sun;
-	} else {
+	} else if (!netlink) {
 	    /* Get rpcbind's address on this transport */
 
 	    memset(&hints, 0, sizeof hints);
@@ -332,8 +351,7 @@ init_transport(struct netconfig *nconf)
 	    hints.ai_protocol = si.si_proto;
 	}
 
-	if ((strcmp(nconf->nc_netid, "local") != 0) &&
-	    (strcmp(nconf->nc_netid, "unix") != 0)) {
+	if (!local && !netlink) {
 	    /*
 	     * If no hosts were specified, just bind to INADDR_ANY.
 	     * Otherwise  make sure 127.0.0.1 is added to the list.
@@ -471,15 +489,8 @@ init_transport(struct netconfig *nconf)
 
 		my_xprt = (SVCXPRT *)svc_tli_create(fd, nconf, &taddr,
 		    RPC_MAXDATASIZE, RPC_MAXDATASIZE);
-		if (my_xprt == (SVCXPRT *)NULL) {
-		    syslog(LOG_ERR, "%s: could not create service",
-			nconf->nc_netid);
-		    goto error;
-		}
 	    }
-	    if (!bound)
-		return 1;
-	} else {
+	} else if (local) {
 	    oldmask = umask(S_IXUSR|S_IXGRP|S_IXOTH);
 	    if (bind(fd, sa, addrlen) < 0) {
 		syslog(LOG_ERR, "cannot bind %s: %m", nconf->nc_netid);
@@ -520,22 +531,25 @@ init_transport(struct netconfig *nconf)
 
 	    my_xprt = (SVCXPRT *)svc_tli_create(fd, nconf, &taddr,
 		RPC_MAXDATASIZE, RPC_MAXDATASIZE);
-	    if (my_xprt == (SVCXPRT *)NULL) {
+	} else {
+		assert(netlink);
+		taddr = netlink_taddr;
+		my_xprt = svc_nl_create("rpcbind");
+	}
+
+	if (my_xprt == (SVCXPRT *)NULL) {
 		syslog(LOG_ERR, "%s: could not create service",
 		    nconf->nc_netid);
 		goto error;
-	    }
 	}
 
 #ifdef PORTMAP
 	/*
 	 * Register both the versions for tcp/ip, udp/ip and local.
 	 */
-	if ((strcmp(nconf->nc_protofmly, NC_INET) == 0 &&
-		(strcmp(nconf->nc_proto, NC_TCP) == 0 ||
-		strcmp(nconf->nc_proto, NC_UDP) == 0)) ||
-		(strcmp(nconf->nc_netid, "unix") == 0) ||
-		(strcmp(nconf->nc_netid, "local") == 0)) {
+	if (!netlink && (local || (strcmp(nconf->nc_protofmly, NC_INET) == 0 &&
+	    (strcmp(nconf->nc_proto, NC_TCP) == 0 ||
+	    strcmp(nconf->nc_proto, NC_UDP) == 0)))) {
 		struct pmaplist *pml;
 
 		if (!svc_register(my_xprt, PMAPPROG, PMAPVERS,
@@ -647,7 +661,7 @@ init_transport(struct netconfig *nconf)
 	/*
 	 * rmtcall only supported on CLTS transports for now.
 	 */
-	if (nconf->nc_semantics == NC_TPI_CLTS) {
+	if (!netlink && nconf->nc_semantics == NC_TPI_CLTS) {
 		status = create_rmtcall_fd(nconf);
 
 #ifdef BIND_DEBUG
@@ -665,7 +679,8 @@ init_transport(struct netconfig *nconf)
 	}
 	return (0);
 error:
-	close(fd);
+	if (fd != -1)
+		close(fd);
 	return (1);
 }
 
diff --git a/usr.sbin/rpcbind/security.c b/usr.sbin/rpcbind/security.c
index 6d899f0a9269..d345ffb510d4 100644
--- a/usr.sbin/rpcbind/security.c
+++ b/usr.sbin/rpcbind/security.c
@@ -145,6 +145,7 @@ is_loopback(struct netbuf *nbuf)
 		    (ntohs(sin6->sin6_port) < IPV6PORT_RESERVED));
 #endif
 	case AF_LOCAL:
+	case AF_NETLINK:
 		return 1;
 	default:
 		break;