From: Masatake YAMATO Date: Fri, 3 Jan 2025 18:50:01 +0000 (+0900) Subject: lsfd: decode protocol numbers of RAW and RAW6 sockets X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=2e45f542dbf9a4bb19b804ae98e3ba7742595012;p=thirdparty%2Futil-linux.git lsfd: decode protocol numbers of RAW and RAW6 sockets NOTE: this chage breaks compatibility of existing -Q expression used in a shell script; the data type of RAW.PROTOCOL has changed from to . With this change, lsfd decodes RAW.PROTOCOL with a built-in table based on linux/in.h and getprotobynumber(3) that may refer to /etc/protocols internally. In addition, this change adds RAW.PROTOCOL.RAW column that holds the original protocol numbers. Signed-off-by: Masatake YAMATO --- diff --git a/lsfd-cmd/lsfd.1.adoc b/lsfd-cmd/lsfd.1.adoc index 39a1312c4..7f8b12099 100644 --- a/lsfd-cmd/lsfd.1.adoc +++ b/lsfd-cmd/lsfd.1.adoc @@ -436,8 +436,13 @@ ICMP echo request id used on the PING socket. POS <``number``>:: File position. -RAW.PROTOCOL <``number``>:: -Protocol number of the raw socket. +RAW.PROTOCOL <``string``>:: +Protocol name of the raw socket (decoded). ++ +NOTE: The data type of this column was <``number``> from v2.39 to v2.41. + +RAW.PROTOCOL.RAW <``number``>:: +Protocol number of the raw socket (raw). RDEV <``string``>:: Device ID (if special file). diff --git a/lsfd-cmd/lsfd.c b/lsfd-cmd/lsfd.c index 4d05c3b27..bca615abd 100644 --- a/lsfd-cmd/lsfd.c +++ b/lsfd-cmd/lsfd.c @@ -341,8 +341,11 @@ static const struct colinfo infos[] = { 0, SCOLS_FL_RIGHT, SCOLS_JSON_NUMBER, N_("tty index of the counterpart") }, [COL_RAW_PROTOCOL] = { "RAW.PROTOCOL", + 0, SCOLS_FL_RIGHT, SCOLS_JSON_STRING, + N_("protocol name of the raw socket (decoded)") }, + [COL_RAW_PROTOCOL_RAW] = { "RAW.PROTOCOL.RAW", 0, SCOLS_FL_RIGHT, SCOLS_JSON_NUMBER, - N_("protocol number of the raw socket") }, + N_("protocol number of the raw socket (raw)") }, [COL_RDEV] = { "RDEV", 0, SCOLS_FL_RIGHT, SCOLS_JSON_STRING, N_("device ID (if special file)") }, diff --git a/lsfd-cmd/lsfd.h b/lsfd-cmd/lsfd.h index 814605a1b..4aa7bf2bb 100644 --- a/lsfd-cmd/lsfd.h +++ b/lsfd-cmd/lsfd.h @@ -111,6 +111,7 @@ enum { COL_POS, COL_PTMX_TTY_INDEX, COL_RAW_PROTOCOL, + COL_RAW_PROTOCOL_RAW, COL_RDEV, COL_SIGNALFD_MASK, COL_SIZE, diff --git a/lsfd-cmd/sock-xinfo.c b/lsfd-cmd/sock-xinfo.c index 438756274..6803300cb 100644 --- a/lsfd-cmd/sock-xinfo.c +++ b/lsfd-cmd/sock-xinfo.c @@ -23,6 +23,7 @@ #include /* open(2) */ #include /* getifaddrs */ #include /* SCNu16 */ +#include /* getprotobyname */ #include /* if_nametoindex */ #include /* ETH_P_* */ #include /* SS_* */ @@ -1436,9 +1437,102 @@ struct raw_xinfo { uint16_t protocol; }; +static const char *raw_decode_protocol(uint16_t proto, bool decoded_as_ipv6) +{ + struct protoent *pent; + + if (proto == 0) { + if (decoded_as_ipv6) + return "hopopts"; /* IPPROTO_HOPOPTS */ + else + return "ip"; /* IPPROTO_IP */ + } + + switch (proto) { + case IPPROTO_ICMP: + return "icmp"; + case IPPROTO_IGMP: + return "igmp"; + case IPPROTO_IPIP: + return "ipip"; + case IPPROTO_TCP: + return "tcp"; + case IPPROTO_EGP: + return "egp"; + case IPPROTO_PUP: + return "pup"; + case IPPROTO_UDP: + return "udp"; + case IPPROTO_IDP: + return "idp"; + case IPPROTO_TP: + return "tp"; + case IPPROTO_DCCP: + return "dccp"; + case IPPROTO_IPV6: + return "ipv6"; + case IPPROTO_RSVP: + return "rsvp"; + case IPPROTO_GRE: + return "gre"; + case IPPROTO_ESP: + return "esp"; + case IPPROTO_AH: + return "ah"; + case IPPROTO_MTP: + return "mtp"; + case IPPROTO_BEETPH: + return "beetph"; + case IPPROTO_ENCAP: + return "encap"; + case IPPROTO_PIM: + return "pim"; + case IPPROTO_COMP: + return "comp"; +#ifdef IPPROTO_L2TP + case IPPROTO_L2TP: + return "l2tp"; +#endif + case IPPROTO_SCTP: + return "sctp"; + case IPPROTO_UDPLITE: + return "udplite"; + case IPPROTO_MPLS: + return "mpls"; +#ifdef IPPROTO_ETHERNET + case IPPROTO_ETHERNET: + return "ethernet"; +#endif + case IPPROTO_RAW: + return "raw"; +#ifdef IPPROTO_MPTCP + case IPPROTO_MPTCP: + return "mptcp"; +#endif + case IPPROTO_ROUTING: + return "routing"; + case IPPROTO_FRAGMENT: + return "fragment"; + case IPPROTO_ICMPV6: + return "icmpv6"; + case IPPROTO_NONE: + return "none"; + case IPPROTO_DSTOPTS: + return "dstopts"; + case IPPROTO_MH: + return "mh"; + } + + pent = getprotobynumber(proto); + if (pent && pent->p_name) + return pent->p_name; + + return NULL; +} + static char *raw_get_name_common(struct sock_xinfo *sock_xinfo, struct sock *sock __attribute__((__unused__)), - const char *port_label) + const char *port_label, bool decode_as_protocol) { char *str = NULL; struct l4_xinfo_class *class = (struct l4_xinfo_class *)sock_xinfo->class; @@ -1452,24 +1546,44 @@ static char *raw_get_name_common(struct sock_xinfo *sock_xinfo, 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 %s=%"PRIu16" laddr=%s", - st_str, - port_label, - raw->protocol, local_s); - else - xasprintf(&str, "state=%s %s=%"PRIu16" laddr=%s raddr=%s", - st_str, - port_label, - raw->protocol, local_s, remote_s); + else { + const char *protocol_str = NULL; + char protocol_buf[ sizeof ("unknown(") + + sizeof (stringify_value(UINT16_MA)) + + sizeof (")") ]; + + if (decode_as_protocol) { + protocol_str = raw_decode_protocol(raw->protocol, + class->family == AF_INET6); + if (protocol_str == NULL) { + snprintf(protocol_buf, sizeof(protocol_buf), + "unknown(%"PRIu16")", raw->protocol); + protocol_str = protocol_buf; + } + } else { + snprintf(protocol_buf, sizeof(protocol_buf), "%"PRIu16, raw->protocol); + protocol_str = protocol_buf; + } + + if (class->is_any_addr(raddr) + || !inet_ntop(class->family, raddr, remote_s, sizeof(remote_s))) + xasprintf(&str, "state=%s %s=%s laddr=%s", + st_str, + port_label, + protocol_str, local_s); + else + xasprintf(&str, "state=%s %s=%s laddr=%s raddr=%s", + st_str, + port_label, + protocol_str, local_s, remote_s); + } return str; } static char *raw_get_name(struct sock_xinfo *sock_xinfo, struct sock *sock __attribute__((__unused__))) { - return raw_get_name_common(sock_xinfo, sock, "protocol"); + return raw_get_name_common(sock_xinfo, sock, "protocol", true); } static char *raw_get_type(struct sock_xinfo *sock_xinfo __attribute__((__unused__)), @@ -1478,6 +1592,29 @@ static char *raw_get_type(struct sock_xinfo *sock_xinfo __attribute__((__unused_ return xstrdup("raw"); } +static bool raw_fill_column_common(struct raw_xinfo *raw, + int column_id, + char **str, + bool decoded_as_ipv6) +{ + const char *pname; + + switch (column_id) { + case COL_RAW_PROTOCOL: + pname = raw_decode_protocol(raw->protocol, decoded_as_ipv6); + if (pname) { + *str = xstrdup(pname); + return true; + } + FALLTHROUGH; + case COL_RAW_PROTOCOL_RAW: + xasprintf(str, "%"PRIu16, raw->protocol); + return true; + } + + return false; +} + static bool raw_fill_column(struct proc *proc __attribute__((__unused__)), struct sock_xinfo *sock_xinfo, struct sock *sock __attribute__((__unused__)), @@ -1489,13 +1626,8 @@ static bool raw_fill_column(struct proc *proc __attribute__((__unused__)), if (l3_fill_column_handler(INET, sock_xinfo, column_id, str)) return true; - if (column_id == COL_RAW_PROTOCOL) { - xasprintf(str, "%"PRIu16, - ((struct raw_xinfo *)sock_xinfo)->protocol); - return true; - } - - return false; + return raw_fill_column_common((struct raw_xinfo *)sock_xinfo, + column_id, str, false); } static struct sock_xinfo *raw_xinfo_scan_line(const struct sock_xinfo_class *class, @@ -1564,7 +1696,7 @@ static void load_xinfo_from_proc_raw(ino_t netns_inode, enum sysfs_byteorder byt static char *ping_get_name(struct sock_xinfo *sock_xinfo, struct sock *sock __attribute__((__unused__))) { - return raw_get_name_common(sock_xinfo, sock, "id"); + return raw_get_name_common(sock_xinfo, sock, "id", false); } static char *ping_get_type(struct sock_xinfo *sock_xinfo __attribute__((__unused__)), @@ -1845,18 +1977,11 @@ static bool raw6_fill_column(struct proc *proc __attribute__((__unused__)), size_t column_index __attribute__((__unused__)), char **str) { - struct raw_xinfo *raw; - if (l3_fill_column_handler(INET6, sock_xinfo, column_id, str)) return true; - raw = (struct raw_xinfo *)sock_xinfo; - if (column_id == COL_RAW_PROTOCOL) { - xasprintf(str, "%"PRIu16, raw->protocol); - return true; - } - - return false; + return raw_fill_column_common((struct raw_xinfo *)sock_xinfo, + column_id, str, true); } static const struct l4_xinfo_class raw6_xinfo_class = { diff --git a/tests/expected/lsfd/mkfds-raw b/tests/expected/lsfd/mkfds-raw index 37baddc77..8e45b1e95 100644 --- a/tests/expected/lsfd/mkfds-raw +++ b/tests/expected/lsfd/mkfds-raw @@ -1,2 +1,6 @@ -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 +3 RAW state=established protocol=st laddr=127.0.0.1 raddr=127.0.0.2 established raw 127.0.0.1 127.0.0.2 st 5 +ASSOC,TYPE,NAME,SOCK.STATE,SOCK.TYPE,INET.LADDR,INET.RADDR,RAW.PROTOCOL,RAW.PROTOCOL.RAW: 0 +3 RAW state=established protocol=tcp laddr=127.0.0.1 raddr=127.0.0.2 established raw 127.0.0.1 127.0.0.2 tcp 6 +ASSOC,TYPE,NAME,SOCK.STATE,SOCK.TYPE,INET.LADDR,INET.RADDR,RAW.PROTOCOL,RAW.PROTOCOL.RAW: 0 +3 RAW state=established protocol=unknown(61) laddr=127.0.0.1 raddr=127.0.0.2 established raw 127.0.0.1 127.0.0.2 61 61 +ASSOC,TYPE,NAME,SOCK.STATE,SOCK.TYPE,INET.LADDR,INET.RADDR,RAW.PROTOCOL,RAW.PROTOCOL.RAW: 0 diff --git a/tests/expected/lsfd/mkfds-raw6 b/tests/expected/lsfd/mkfds-raw6 index 2d77e8f3b..5ba44ae02 100644 --- a/tests/expected/lsfd/mkfds-raw6 +++ b/tests/expected/lsfd/mkfds-raw6 @@ -1,2 +1,6 @@ -3 RAWv6 state=established protocol=5 laddr=::1 raddr=::ffff:127.0.0.1 established raw ::1 ::ffff:127.0.0.1 5 -ASSOC,TYPE,NAME,SOCK.STATE,SOCK.TYPE,INET6.LADDR,INET6.RADDR,RAW.PROTOCOL: 0 +3 RAWv6 state=established protocol=st laddr=::1 raddr=::ffff:127.0.0.1 established raw ::1 ::ffff:127.0.0.1 st 5 +ASSOC,TYPE,NAME,SOCK.STATE,SOCK.TYPE,INET6.LADDR,INET6.RADDR,RAW.PROTOCOL,RAW.PROTOCOL.RAW: 0 +3 RAWv6 state=established protocol=tcp laddr=::1 raddr=::ffff:127.0.0.1 established raw ::1 ::ffff:127.0.0.1 tcp 6 +ASSOC,TYPE,NAME,SOCK.STATE,SOCK.TYPE,INET6.LADDR,INET6.RADDR,RAW.PROTOCOL,RAW.PROTOCOL.RAW: 0 +3 RAWv6 state=established protocol=unknown(61) laddr=::1 raddr=::ffff:127.0.0.1 established raw ::1 ::ffff:127.0.0.1 61 61 +ASSOC,TYPE,NAME,SOCK.STATE,SOCK.TYPE,INET6.LADDR,INET6.RADDR,RAW.PROTOCOL,RAW.PROTOCOL.RAW: 0 diff --git a/tests/ts/lsfd/mkfds-raw b/tests/ts/lsfd/mkfds-raw index 577034044..0ff246f5e 100755 --- a/tests/ts/lsfd/mkfds-raw +++ b/tests/ts/lsfd/mkfds-raw @@ -31,19 +31,30 @@ ts_cd "$TS_OUTDIR" PID= FD=3 EXPR='(TYPE == "RAW") and (FD == 3)' -PROTOCOL=5 +test_lsfd_raw() { - coproc MKFDS { "$TS_HELPER_MKFDS" raw $FD protocol=$PROTOCOL; } + local protocol=$1 + + 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 \ + -o ASSOC,TYPE,NAME,SOCK.STATE,SOCK.TYPE,INET.LADDR,INET.RADDR,RAW.PROTOCOL,RAW.PROTOCOL.RAW \ -p "${PID}" -Q "${EXPR}" - echo 'ASSOC,TYPE,NAME,SOCK.STATE,SOCK.TYPE,INET.LADDR,INET.RADDR,RAW.PROTOCOL': $? + echo 'ASSOC,TYPE,NAME,SOCK.STATE,SOCK.TYPE,INET.LADDR,INET.RADDR,RAW.PROTOCOL,RAW.PROTOCOL.RAW': $? echo DONE >&"${MKFDS[1]}" fi wait "${MKFDS_PID}" +} + +{ + # 5 is only in /etc/protocol + # 6 is in linux/in.h. + # 61 is not in neither sources. + for p in 5 6 61; do + test_lsfd_raw $p + done } > "$TS_OUTPUT" 2>&1 ts_finalize diff --git a/tests/ts/lsfd/mkfds-raw6 b/tests/ts/lsfd/mkfds-raw6 index 1eddea28f..d50a5d873 100755 --- a/tests/ts/lsfd/mkfds-raw6 +++ b/tests/ts/lsfd/mkfds-raw6 @@ -32,19 +32,30 @@ ts_cd "$TS_OUTDIR" PID= FD=3 EXPR='(TYPE == "RAWv6") and (FD == 3)' -PROTOCOL=5 +test_lsfd_raw6() { - coproc MKFDS { "$TS_HELPER_MKFDS" raw6 $FD protocol=$PROTOCOL; } + local protocol=$1 + + coproc MKFDS { "$TS_HELPER_MKFDS" raw6 $FD protocol=$protocol; } if read -r -u "${MKFDS[0]}" PID; then ${TS_CMD_LSFD} -n \ - -o ASSOC,TYPE,NAME,SOCK.STATE,SOCK.TYPE,INET6.LADDR,INET6.RADDR,RAW.PROTOCOL \ + -o ASSOC,TYPE,NAME,SOCK.STATE,SOCK.TYPE,INET6.LADDR,INET6.RADDR,RAW.PROTOCOL,RAW.PROTOCOL.RAW \ -p "${PID}" -Q "${EXPR}" - echo 'ASSOC,TYPE,NAME,SOCK.STATE,SOCK.TYPE,INET6.LADDR,INET6.RADDR,RAW.PROTOCOL': $? + echo 'ASSOC,TYPE,NAME,SOCK.STATE,SOCK.TYPE,INET6.LADDR,INET6.RADDR,RAW.PROTOCOL,RAW.PROTOCOL.RAW': $? echo DONE >&"${MKFDS[1]}" fi wait "${MKFDS_PID}" +} + +{ + # 5 is only in /etc/protocol + # 6 is in linux/in.h. + # 61 is not in neither sources. + for p in 5 6 61; do + test_lsfd_raw6 $p + done } > "$TS_OUTPUT" 2>&1 ts_finalize