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>
#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);
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)
"/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);
+}
*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_]]
+
POS <``number``>::
File position.
+RAW.PROTOCOL <``number``>>::
+Protocol number of the raw socket.
+
RDEV <``string``>::
Device ID (if special file).
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,
COL_PIDFD_NSPID,
COL_PIDFD_PID,
COL_POS,
+ COL_RAW_PROTOCOL,
COL_RDEV,
COL_SIZE,
COL_SOCK_LISTENING,
--- /dev/null
+ 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
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_)
{
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",
--- /dev/null
+#!/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