Skip to contentSkip to conversation

ss: remove implicit dependency on rpcinfo

PATCH Applied Andrea Claudi 2 participants 4 messages Mar 16, 2022 – Mar 24, 2022

Subsystems (2)
lore
Share & tools
lore
#0 lore raw

cover ss: remove implicit dependency on rpcinfo

ss uses rpcinfo to get info about rpc service sockets. However, rpcinfo is not part of iproute2 and it's an implicit dependency for ss.

This series uses libtirpc[1] API to implement the same feature of rpcinfo for ss. This makes it possible to get info about rpc sockets, provided ss is compiled with libtirpc support.

As a nice byproduct, this makes ss provide info about some ipv6 rpc sockets that are not displayed using 'rpcinfo -p'.

- patch 1 adds a configure function to check for libtirpc;
- patch 2 actually rework ss to use libtirpc.

[1] https://git.linux-nfs.org/?p=steved/libtirpc.git

Andrea Claudi (2):
configure: add check_libtirpc()
ss: remove an implicit dependency on rpcinfo

 configure | 16 ++++++++++
 misc/ss.c | 93 +++++++++++++++++++++++++++++++++++++++++++------------
 2 files changed, 89 insertions(+), 20 deletions(-)
Signature · 1 line
2.35.1
#1 lore raw

PATCH 1/2 configure: add check_libtirpc()

This patch adds a configure function to check if libtirpc is installed on the build system. If this is the case, it makes iproute2 to compile with libtirpc support.

---
 configure | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)
configure +16 -0
index 8ddff43c..440facb7 100755
@@ -395,6 +395,19 @@ check_selinux()
 	fi
 }
 
+check_tirpc()
+{
+	if ${PKG_CONFIG} libtirpc --exists; then
+		echo "HAVE_RPC:=y" >>$CONFIG
+		echo "yes"
+
+		echo 'LDLIBS +=' `${PKG_CONFIG} --libs libtirpc` >>$CONFIG
+		echo 'CFLAGS += -DHAVE_RPC' `${PKG_CONFIG} --cflags libtirpc` >>$CONFIG
+	else
+		echo "no"
+	fi
+}
+
 check_mnl()
 {
 	if ${PKG_CONFIG} libmnl --exists; then
@@ -600,6 +613,9 @@ check_name_to_handle_at
 echo -n "SELinux support: "
 check_selinux
 
+echo -n "libtirpc support: "
+check_tirpc
+
 echo -n "libbpf support: "
 check_libbpf
 
Signature · 1 line
2.35.1
#2 lore raw

PATCH 2/2 ss: remove an implicit dependency on rpcinfo

In reply to Andrea Claudi

ss uses rpcinfo to get info about rpc services socket. This makes it dependent on a tool not included in iproute2, and makes it impossible to get info on rpc sockets if rpcinfo is not installed.

This reworks init_service_resolver() to use libtirpc, thus avoiding the implicity dependency on rpcinfo. Moreover, this also makes it possible to display info about ipv6 rpc socket that are not included in the rpcinfo -p output.

For example, before this patch:

$ ss -rtap
LISTEN          0               5                                                        localhost:ipp                                        [::]:*                     users:(("cupsd",pid=1600,fd=9))
LISTEN          0               64                                                            [::]:34265                                      [::]:*
LISTEN          0               64                                                            [::]:rpc.nfs_acl                                [::]:*
LISTEN          0               128                                                           [::]:42253                                      [::]:*                     users:(("rpc.statd",pid=146164,fd=12))

After this patch:

$ ss -rtap
LISTEN          0               5                                                        localhost:ipp                                        [::]:*                     users:(("cupsd",pid=1600,fd=9))
LISTEN          0               64                                                            [::]:rpc.nlockmgr                               [::]:*
LISTEN          0               64                                                            [::]:rpc.nfs_acl                                [::]:*
LISTEN          0               128                                                           [::]:rpc.status                                 [::]:*                     users:(("rpc.statd",pid=146164,fd=12))
---
 misc/ss.c | 93 +++++++++++++++++++++++++++++++++++++++++++------------
 1 file changed, 73 insertions(+), 20 deletions(-)
misc/ss.c +73 -20
index 5e7e84ee..4b3ca9c4 100644
@@ -55,6 +55,11 @@
 #include <linux/tls.h>
 #include <linux/mptcp.h>
 
+#if HAVE_RPC
+#include <rpc/rpc.h>
+#include <rpc/xdr.h>
+#endif
+
 /* AF_VSOCK/PF_VSOCK is only provided since glibc 2.18 */
 #ifndef PF_VSOCK
 #define PF_VSOCK 40
@@ -192,8 +197,12 @@ static struct {
 } buffer;
 
 static const char *TCP_PROTO = "tcp";
-static const char *SCTP_PROTO = "sctp";
 static const char *UDP_PROTO = "udp";
+#ifdef HAVE_RPC
+static const char *TCP6_PROTO = "tcp6";
+static const char *UDP6_PROTO = "udp6";
+static const char *SCTP_PROTO = "sctp";
+#endif
 static const char *RAW_PROTO = "raw";
 static const char *dg_proto;
 
@@ -1479,45 +1488,87 @@ struct scache {
 
 static struct scache *rlist;
 
+#ifdef HAVE_RPC
+static CLIENT *rpc_client_create(rpcprog_t prog, rpcvers_t vers)
+{
+	struct netbuf nbuf;
+	struct sockaddr_un saddr;
+	int sock;
+
+	memset(&saddr, 0, sizeof(saddr));
+	sock = socket(AF_LOCAL, SOCK_STREAM, 0);
+	if (sock < 0)
+		return NULL;
+
+	saddr.sun_family = AF_LOCAL;
+	strcpy(saddr.sun_path, _PATH_RPCBINDSOCK);
+	nbuf.len = SUN_LEN(&saddr);
+	nbuf.maxlen = sizeof(struct sockaddr_un);
+	nbuf.buf = &saddr;
+
+	return clnt_vc_create(sock, &nbuf, prog, vers, 0, 0);
+}
+
 static void init_service_resolver(void)
 {
-	char buf[128];
-	FILE *fp = popen("/usr/sbin/rpcinfo -p 2>/dev/null", "r");
+	struct rpcblist *rhead = NULL;
+	struct timeval timeout;
+	struct rpcent *rpc;
+	enum clnt_stat res;
+	CLIENT *client;
 
-	if (!fp)
+	timeout.tv_sec = 5;
+	timeout.tv_usec = 0;
+
+	client = rpc_client_create(PMAPPROG, RPCBVERS4);
+	if (!client)
 		return;
 
-	if (!fgets(buf, sizeof(buf), fp)) {
-		pclose(fp);
+	res = clnt_call(client, RPCBPROC_DUMP, (xdrproc_t)xdr_void, NULL,
+			(xdrproc_t)xdr_rpcblist_ptr, (char *)&rhead,
+			timeout);
+	if (res != RPC_SUCCESS)
 		return;
-	}
-	while (fgets(buf, sizeof(buf), fp) != NULL) {
-		unsigned int progn, port;
-		char proto[128], prog[128] = "rpc.";
+
+	for (; rhead; rhead = rhead->rpcb_next) {
+		char prog[128] = "rpc.";
 		struct scache *c;
+		int hport, lport, ok;
 
-		if (sscanf(buf, "%u %*d %s %u %s",
-			   &progn, proto, &port, prog+4) != 4)
+		c = malloc(sizeof(*c));
+		if (!c)
 			continue;
 
-		if (!(c = malloc(sizeof(*c))))
+		ok = sscanf(rhead->rpcb_map.r_addr, "::.%d.%d", &hport, &lport);
+		if (!ok)
+			ok = sscanf(rhead->rpcb_map.r_addr, "0.0.0.0.%d.%d",
+				    &hport, &lport);
+		if (!ok)
 			continue;
+		c->port = hport << 8 | lport;
 
-		c->port = port;
-		c->name = strdup(prog);
-		if (strcmp(proto, TCP_PROTO) == 0)
+		if (strcmp(rhead->rpcb_map.r_netid, TCP_PROTO) == 0 ||
+		    strcmp(rhead->rpcb_map.r_netid, TCP6_PROTO) == 0)
 			c->proto = TCP_PROTO;
-		else if (strcmp(proto, UDP_PROTO) == 0)
+		else if (strcmp(rhead->rpcb_map.r_netid, UDP_PROTO) == 0 ||
+			 strcmp(rhead->rpcb_map.r_netid, UDP6_PROTO) == 0)
 			c->proto = UDP_PROTO;
-		else if (strcmp(proto, SCTP_PROTO) == 0)
+		else if (strcmp(rhead->rpcb_map.r_netid, SCTP_PROTO) == 0)
 			c->proto = SCTP_PROTO;
 		else
-			c->proto = NULL;
+			continue;
+
+		rpc = getrpcbynumber(rhead->rpcb_map.r_prog);
+		if (rpc) {
+			strncat(prog, rpc->r_name, 128 - strlen(prog));
+			c->name = strdup(prog);
+		}
+
 		c->next = rlist;
 		rlist = c;
 	}
-	pclose(fp);
 }
+#endif
 
 /* Even do not try default linux ephemeral port ranges:
  * default /etc/services contains so much of useless crap
@@ -5668,9 +5719,11 @@ int main(int argc, char *argv[])
 	filter_states_set(&current_filter, state_filter);
 	filter_merge_defaults(&current_filter);
 
+#ifdef HAVE_RPC
 	if (!numeric && resolve_hosts &&
 	    (current_filter.dbs & (UNIX_DBM|INET_L4_DBM)))
 		init_service_resolver();
+#endif
 
 	if (current_filter.dbs == 0) {
 		fprintf(stderr, "ss: no socket tables to show with such filter.\n");
Signature · 1 line
2.35.1
#3 lore raw
In reply to Andrea Claudi
This series was applied to iproute2/iproute2-next.git (main) by David Ahern <[email protected]>:

Hello:

This series was applied to iproute2/iproute2-next.git (main) by David Ahern <[email protected]>:

Quoted 8 lines · On Wed, 16 Mar 2022 19:52:12 +0100 you wrote:

ss uses rpcinfo to get info about rpc service sockets. However, rpcinfo is not part of iproute2 and it's an implicit dependency for ss.

This series uses libtirpc[1] API to implement the same feature of rpcinfo for ss. This makes it possible to get info about rpc sockets, provided ss is compiled with libtirpc support.

[...]

Here is the summary with links:
- [iproute2-next,1/2] configure: add check_libtirpc()

    https://git.kernel.org/pub/scm/network/iproute2/iproute2-next.git/commit/?id=1ee309a49aa0
  - [iproute2-next,2/2] ss: remove an implicit dependency on rpcinfo
    https://git.kernel.org/pub/scm/network/iproute2/iproute2-next.git/commit/?id=292509f95dd4

You are awesome, thank you!

Signature · 2 lines
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/patchwork/pwbot.html