From: Masatake YAMATO Date: Wed, 1 Feb 2023 12:53:57 +0000 (+0900) Subject: lsfd: use extra information loaded from /proc/net/raw X-Git-Tag: v2.39-rc1~83^2~3 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=0188afb3266426df59fe61fb77fdca833b90a792;p=thirdparty%2Futil-linux.git lsfd: use extra information loaded from /proc/net/raw RAW.PROTOCOL field is added. Thomas Weißschuh suggested making the test script executable. Signed-off-by: Masatake YAMATO --- diff --git a/misc-utils/lsfd-sock-xinfo.c b/misc-utils/lsfd-sock-xinfo.c index 0a3caa9c04..e7f6e74d10 100644 --- a/misc-utils/lsfd-sock-xinfo.c +++ b/misc-utils/lsfd-sock-xinfo.c @@ -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); +} diff --git a/misc-utils/lsfd.1.adoc b/misc-utils/lsfd.1.adoc index c82461e9af..6abedb204f 100644 --- a/misc-utils/lsfd.1.adoc +++ b/misc-utils/lsfd.1.adoc @@ -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). diff --git a/misc-utils/lsfd.c b/misc-utils/lsfd.c index e6da1cb897..251d1dc938 100644 --- a/misc-utils/lsfd.c +++ b/misc-utils/lsfd.c @@ -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, diff --git a/misc-utils/lsfd.h b/misc-utils/lsfd.h index 484e9c27f7..3b12c60c63 100644 --- a/misc-utils/lsfd.h +++ b/misc-utils/lsfd.h @@ -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 index 0000000000..e8bc41a015 --- /dev/null +++ b/tests/expected/lsfd/mkfds-raw @@ -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 diff --git a/tests/helpers/test_mkfds.c b/tests/helpers/test_mkfds.c index 49a1582fbf..8118fc94f9 100644 --- a/tests/helpers/test_mkfds.c +++ b/tests/helpers/test_mkfds.c @@ -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 index 0000000000..2c33abcd94 --- /dev/null +++ b/tests/ts/lsfd/mkfds-raw @@ -0,0 +1,49 @@ +#!/bin/bash +# +# Copyright (C) 2023 Masatake YAMATO +# +# 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