]> git.ipfire.org Git - thirdparty/util-linux.git/commitdiff
lsfd: use extra information loaded from /proc/net/raw
authorMasatake YAMATO <yamato@redhat.com>
Wed, 1 Feb 2023 12:53:57 +0000 (21:53 +0900)
committerMasatake YAMATO <yamato@redhat.com>
Fri, 10 Feb 2023 04:09:19 +0000 (13:09 +0900)
RAW.PROTOCOL field is added.

Thomas Weißschuh <thomas@t-8ch.de> suggested making the test
script executable.

Signed-off-by: Masatake YAMATO <yamato@redhat.com>
misc-utils/lsfd-sock-xinfo.c
misc-utils/lsfd.1.adoc
misc-utils/lsfd.c
misc-utils/lsfd.h
tests/expected/lsfd/mkfds-raw [new file with mode: 0644]
tests/helpers/test_mkfds.c
tests/ts/lsfd/mkfds-raw [new file with mode: 0755]

index 0a3caa9c048e9dd5e21146be97b190db65cdf35d..e7f6e74d108b71d11d847bf4e45380057d085c1a 100644 (file)
@@ -38,6 +38,7 @@
 #include "lsfd-sock.h"
 
 static void load_xinfo_from_proc_unix(ino_t netns_inode);
+static void load_xinfo_from_proc_raw(ino_t netns_inode);
 static void load_xinfo_from_proc_tcp(ino_t netns_inode);
 static void load_xinfo_from_proc_udp(ino_t netns_inode);
 
@@ -78,6 +79,7 @@ static void load_sock_xinfo_no_nsswitch(ino_t netns)
        load_xinfo_from_proc_unix(netns);
        load_xinfo_from_proc_tcp(netns);
        load_xinfo_from_proc_udp(netns);
+       load_xinfo_from_proc_raw(netns);
 }
 
 static void load_sock_xinfo_with_fd(int fd, ino_t netns)
@@ -795,3 +797,122 @@ static void load_xinfo_from_proc_udp(ino_t netns_inode)
                                     "/proc/net/udp",
                                     &udp_xinfo_class);
 }
+
+/*
+ * RAW
+ */
+struct raw_xinfo {
+       struct l4_xinfo l4;
+       uint16_t protocol;
+};
+
+static char *raw_get_name(struct sock_xinfo *sock_xinfo,
+                         struct sock *sock  __attribute__((__unused__)))
+{
+       char *str = NULL;
+       struct l4_xinfo_class *class = (struct l4_xinfo_class *)sock_xinfo->class;
+       struct raw_xinfo *raw = ((struct raw_xinfo *)sock_xinfo);
+       struct l4_xinfo *l4 = &raw->l4;
+       const char *st_str = tcp_decode_state(l4->st);
+       void *laddr = class->get_addr(l4, L4_LOCAL);
+       void *raddr = class->get_addr(l4, L4_REMOTE);
+       char local_s[BUFSIZ];
+       char remote_s[BUFSIZ];
+
+       if (!inet_ntop(class->family, laddr, local_s, sizeof(local_s)))
+               xasprintf(&str, "state=%s", st_str);
+       else if (class->is_any_addr(raddr)
+                || !inet_ntop(class->family, raddr, remote_s, sizeof(remote_s)))
+               xasprintf(&str, "state=%s protocol=%u laddr=%s",
+                         st_str,
+                         raw->protocol, local_s);
+       else
+               xasprintf(&str, "state=%s protocol=%u laddr=%s raddr=%s",
+                         st_str,
+                         raw->protocol, local_s, remote_s);
+       return str;
+}
+
+static char *raw_get_type(struct sock_xinfo *sock_xinfo __attribute__((__unused__)),
+                         struct sock *sock __attribute__((__unused__)))
+{
+       return strdup("raw");
+}
+
+static bool raw_fill_column(struct proc *proc __attribute__((__unused__)),
+                           struct sock_xinfo *sock_xinfo,
+                           struct sock *sock __attribute__((__unused__)),
+                           struct libscols_line *ln __attribute__((__unused__)),
+                           int column_id,
+                           size_t column_index __attribute__((__unused__)),
+                           char **str)
+{
+       if (l3_fill_column_handler(INET, sock_xinfo, column_id, str))
+               return true;
+
+       if (column_id == COL_RAW_PROTOCOL) {
+               xasprintf(str, "%u",
+                         (unsigned int)(((struct raw_xinfo *)sock_xinfo)->protocol));
+               return true;
+       }
+
+       return false;
+}
+
+static struct sock_xinfo *raw_xinfo_scan_line(const struct sock_xinfo_class *class,
+                                             char * line,
+                                             ino_t netns_inode,
+                                             enum sysfs_byteorder byteorder)
+{
+       unsigned long local_addr;
+       unsigned long protocol;
+       unsigned long remote_addr;
+       unsigned long st;
+       unsigned long long inode;
+       struct raw_xinfo *raw;
+       struct inet_xinfo *inet;
+       struct sock_xinfo *sock;
+
+       if (sscanf(line, "%*d: %lx:%lx %lx:%*x %lx %*x:%*x %*x:%*x %*x %*u %*u %lld",
+                  &local_addr, &protocol, &remote_addr,
+                  &st, &inode) != 5)
+               return NULL;
+
+       if (inode == 0)
+               return NULL;
+
+       raw = xcalloc(1, sizeof(struct raw_xinfo));
+       inet = &raw->l4.inet;
+       sock = &inet->sock;
+       sock->class = class;
+       sock->inode = (ino_t)inode;
+       sock->netns_inode = netns_inode;
+       inet->local_addr.s_addr = kernel32_to_cpu(byteorder, local_addr);
+       inet->remote_addr.s_addr = kernel32_to_cpu(byteorder, remote_addr);
+       raw->protocol = protocol;
+       raw->l4.st = st;
+
+       return sock;
+}
+
+static const struct l4_xinfo_class raw_xinfo_class = {
+       .sock = {
+               .get_name = raw_get_name,
+               .get_type = raw_get_type,
+               .get_state = tcp_get_state,
+               .get_listening = NULL,
+               .fill_column = raw_fill_column,
+               .free = NULL,
+       },
+       .scan_line = raw_xinfo_scan_line,
+       .get_addr = tcp_xinfo_get_addr,
+       .is_any_addr = tcp_xinfo_is_any_addr,
+       .family = AF_INET,
+};
+
+static void load_xinfo_from_proc_raw(ino_t netns_inode)
+{
+       load_xinfo_from_proc_inet_L4(netns_inode,
+                                    "/proc/net/raw",
+                                    &raw_xinfo_class);
+}
index c82461e9afadc9c22df84d76c22890b03246e055..6abedb204ff4052c465e9401661dc2fd2811b40b 100644 (file)
@@ -211,6 +211,9 @@ pid=_TARGET-PID_ comm=_TARGET-COMMAND_ nspid=_TARGET-NSPIDS_
 *lsfd* extracts _TARGET-PID_ and _TARGET-NSPIDS_ from
 ``/proc/``_pid_``/fdinfo/``_fd_.
 +
+RAW:::
+state=_SOCK.STATE_[ protocol=_RAW.PROTOCOL_ [ laddr=_INET.LADDR_ [ raddr=_INET.RADDR_]]
++
 TCP:::
 state=_SOCK.STATE_[ laddr=_TCP.LADDR_ [ raddr=_TCP.RADDR_]]
 +
@@ -270,6 +273,9 @@ PID of the process targeted by the pidfd.
 POS <``number``>::
 File position.
 
+RAW.PROTOCOL <``number``>>::
+Protocol number of the raw socket.
+
 RDEV <``string``>::
 Device ID (if special file).
 
index e6da1cb89733b255af64147456aa11e4fadfaa51..251d1dc93802a53fdf09c2053a3b713d01b151d9 100644 (file)
@@ -187,6 +187,8 @@ static const struct colinfo infos[] = {
                N_("PID of the process targeted by the pidfd") },
        [COL_POS]     = { "POS",      5, SCOLS_FL_RIGHT, SCOLS_JSON_NUMBER,
                N_("file position") },
+       [COL_RAW_PROTOCOL]={ "RAW.PROTOCOL",0,SCOLS_FL_RIGHT,SCOLS_JSON_NUMBER,
+               N_("protocol number of the raw socket") },
        [COL_RDEV]    = { "RDEV",     0, SCOLS_FL_RIGHT, SCOLS_JSON_STRING,
                N_("device ID (if special file)") },
        [COL_SIZE]    = { "SIZE",     4, SCOLS_FL_RIGHT, SCOLS_JSON_NUMBER,
index 484e9c27f7d590dc33c74f5aa44b250ca9a5eecd..3b12c60c63e6ac2f577172074014217c55d70647 100644 (file)
@@ -68,6 +68,7 @@ enum {
        COL_PIDFD_NSPID,
        COL_PIDFD_PID,
        COL_POS,
+       COL_RAW_PROTOCOL,
        COL_RDEV,
        COL_SIZE,
        COL_SOCK_LISTENING,
diff --git a/tests/expected/lsfd/mkfds-raw b/tests/expected/lsfd/mkfds-raw
new file mode 100644 (file)
index 0000000..e8bc41a
--- /dev/null
@@ -0,0 +1,2 @@
+    3  RAW state=established protocol=5 laddr=127.0.0.1 raddr=127.0.0.2 established       raw  127.0.0.1  127.0.0.2            5
+ASSOC,TYPE,NAME,SOCK.STATE,SOCK.TYPE,INET.LADDR,INET.RADDR,RAW.PROTOCOL: 0
index 49a1582fbfc53b3b4b7103e5a1d913177bf0dea3..8118fc94f9b46735b4989e0a2aa52ea12856e1a3 100644 (file)
@@ -1505,6 +1505,59 @@ static void *make_udp(const struct factory *factory, struct fdesc fdescs[],
        return NULL;
 }
 
+static void *make_raw(const struct factory *factory, struct fdesc fdescs[],
+                                   int argc, char ** argv)
+{
+       struct arg protocol = decode_arg("protocol", factory->params, argc, argv);
+       int iprotocol = ARG_INTEGER(protocol);
+       int ssd;
+       struct sockaddr_in sin;
+
+       free_arg(&protocol);
+
+       ssd = socket(AF_INET, SOCK_RAW, iprotocol);
+       if (ssd < 0)
+               err(EXIT_FAILURE,
+                   _("failed to make a udp socket for server"));
+
+       if (ssd != fdescs[0].fd) {
+               if (dup2(ssd, fdescs[0].fd) < 0) {
+                       int e = errno;
+                       close(ssd);
+                       errno = e;
+                       err(EXIT_FAILURE, "failed to dup %d -> %d", ssd, fdescs[0].fd);
+               }
+               close(ssd);
+               ssd = fdescs[0].fd;
+       }
+
+       memset(&sin, 0, sizeof(sin));
+       sin.sin_family = AF_INET;
+       sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+       if (bind(ssd, &sin, sizeof(sin)) < 0) {
+               int e = errno;
+               close(ssd);
+               errno = e;
+               err(EXIT_FAILURE, "failed in bind(2)");
+       }
+
+       sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK + 1);
+       if (connect(ssd, &sin, sizeof(sin)) < 0) {
+               int e = errno;
+               close(ssd);
+               errno = e;
+               err(EXIT_FAILURE, "failed in connect(2)");
+       }
+
+       fdescs[0] = (struct fdesc) {
+               .fd    = fdescs[0].fd,
+               .close = close_fdesc,
+               .data  = NULL,
+       };
+
+       return NULL;
+}
+
 static void *make_netns(const struct factory *factory _U_, struct fdesc fdescs[],
                        int argc _U_, char ** argv _U_)
 {
@@ -1895,6 +1948,24 @@ static const struct factory factories[] = {
                        PARAM_END
                }
        },
+       {
+               .name = "raw",
+               .desc = "AF_INET+SOCK_RAW sockets",
+               .priv = true,
+               .N    = 1,
+               .EX_N = 0,
+               .make = make_raw,
+               .params = (struct parameter []) {
+                       {
+                               .name = "protocol",
+                               .type = PTYPE_INTEGER,
+                               .desc = "protocol passed to socket(AF_INET, SOCK_RAW, protocol)",
+                               .defv.integer = IPPROTO_IPIP,
+                       },
+                       PARAM_END
+               }
+
+       },
        {
                .name = "netns",
                .desc = "open a file specifying a netns",
diff --git a/tests/ts/lsfd/mkfds-raw b/tests/ts/lsfd/mkfds-raw
new file mode 100755 (executable)
index 0000000..2c33abc
--- /dev/null
@@ -0,0 +1,49 @@
+#!/bin/bash
+#
+# Copyright (C) 2023 Masatake YAMATO <yamato@redhat.com>
+#
+# This file is part of util-linux.
+#
+# This file is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This file is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+TS_TOPDIR="${0%/*}/../.."
+TS_DESC="RAW sockets"
+
+. "$TS_TOPDIR"/functions.sh
+ts_init "$*"
+
+ts_skip_nonroot
+
+ts_check_test_command "$TS_CMD_LSFD"
+ts_check_test_command "$TS_HELPER_MKFDS"
+ts_check_native_byteorder
+
+ts_cd "$TS_OUTDIR"
+
+PID=
+FD=3
+EXPR='(TYPE == "RAW") and (FD == 3)'
+PROTOCOL=5
+
+{
+    coproc MKFDS { "$TS_HELPER_MKFDS" raw $FD protocol=$PROTOCOL; }
+    if read -r -u "${MKFDS[0]}" PID; then
+       ${TS_CMD_LSFD} -n \
+                      -o ASSOC,TYPE,NAME,SOCK.STATE,SOCK.TYPE,INET.LADDR,INET.RADDR,RAW.PROTOCOL \
+                      -p "${PID}" -Q "${EXPR}"
+       echo 'ASSOC,TYPE,NAME,SOCK.STATE,SOCK.TYPE,INET.LADDR,INET.RADDR,RAW.PROTOCOL': $?
+    fi
+
+    kill -CONT "${PID}"
+    wait "${MKFDS_PID}"
+} > "$TS_OUTPUT" 2>&1
+
+ts_finalize