diff options
author | Karel Zak <kzak@redhat.com> | 2024-04-08 09:55:59 +0200 |
---|---|---|
committer | Karel Zak <kzak@redhat.com> | 2024-04-08 09:55:59 +0200 |
commit | 671b8b058b02f2dd44ede6317f9cfe6cf09cac12 (patch) | |
tree | 91530cc3e7702988fa26ba0541db95ee4fcd67af | |
parent | 44b92ef3bb950f5680c5febcca5d4b47e67c628c (diff) | |
parent | 099a58dbde6b349c4b5fbebd5116337b2ef2f2fd (diff) | |
download | util-linux-671b8b058b02f2dd44ede6317f9cfe6cf09cac12.tar.gz |
Merge branch 'test_mkfds-sockdiag-for-master' of https://github.com/masatake/util-linux
* 'test_mkfds-sockdiag-for-master' of https://github.com/masatake/util-linux:
tests: (test_mkfds::sockdiag) verify the recieved message to detect whether the socket is usable or not
lsfd: add LSFD_DEBUG env var for debugging
tests: (lsfd) skip some cases if NETLINK_SOCK_DIAG for AF_UNIX is not available
tests: (test_mkfds::sockdiag) new factory
tests: (lsfd-functions.bash,cosmetic) unify the style to define functions
tests: (lsfd) fix typoes in an error name
-rw-r--r-- | misc-utils/lsfd-sock-xinfo.c | 51 | ||||
-rw-r--r-- | misc-utils/lsfd.c | 10 | ||||
-rw-r--r-- | misc-utils/lsfd.h | 15 | ||||
-rw-r--r-- | tests/helpers/test_mkfds.c | 150 | ||||
-rw-r--r-- | tests/ts/lsfd/lsfd-functions.bash | 33 | ||||
-rwxr-xr-x | tests/ts/lsfd/mkfds-ping | 2 | ||||
-rwxr-xr-x | tests/ts/lsfd/mkfds-socketpair | 3 | ||||
-rwxr-xr-x | tests/ts/lsfd/mkfds-unix-stream-requiring-sockdiag | 2 |
8 files changed, 253 insertions, 13 deletions
diff --git a/misc-utils/lsfd-sock-xinfo.c b/misc-utils/lsfd-sock-xinfo.c index 8ee57e6b1f..9422d4b98c 100644 --- a/misc-utils/lsfd-sock-xinfo.c +++ b/misc-utils/lsfd-sock-xinfo.c @@ -179,9 +179,12 @@ static void load_sock_xinfo_no_nsswitch(struct netns *nsobj) load_xinfo_from_proc_packet(netns); diagsd = socket(AF_NETLINK, SOCK_DGRAM, NETLINK_SOCK_DIAG); + DBG(ENDPOINTS, ul_debug("made a diagnose socket [fd=%d; %s]", diagsd, + (diagsd >= 0)? "successful": strerror(errno))); if (diagsd >= 0) { load_xinfo_from_diag_unix(diagsd, netns); close(diagsd); + DBG(ENDPOINTS, ul_debug("close the diagnose socket")); } if (nsobj) @@ -337,6 +340,7 @@ static void send_diag_request(int diagsd, void *req, size_t req_size, bool (*cb)(ino_t, size_t, void *), ino_t netns) { + int r; struct sockaddr_nl nladdr = { .nl_family = AF_NETLINK, }; @@ -361,30 +365,45 @@ static void send_diag_request(int diagsd, void *req, size_t req_size, __attribute__((aligned(sizeof(void *)))) uint8_t buf[8192]; - if (sendmsg(diagsd, &mhd, 0) < 0) + r = sendmsg(diagsd, &mhd, 0); + DBG(ENDPOINTS, ul_debug("sendmsg [rc=%d; %s]", + r, (r >= 0)? "successful": strerror(errno))); + if (r < 0) return; for (;;) { const struct nlmsghdr *h; - int r = recvfrom(diagsd, buf, sizeof(buf), 0, NULL, NULL); + r = recvfrom(diagsd, buf, sizeof(buf), 0, NULL, NULL); + DBG(ENDPOINTS, ul_debug("recvfrom [rc=%d; %s]", + r, (r >= 0)? "successful": strerror(errno))); if (r < 0) return; h = (void *) buf; + DBG(ENDPOINTS, ul_debug(" OK: %d", NLMSG_OK(h, (size_t)r))); if (!NLMSG_OK(h, (size_t)r)) return; for (; NLMSG_OK(h, (size_t)r); h = NLMSG_NEXT(h, r)) { - if (h->nlmsg_type == NLMSG_DONE) + if (h->nlmsg_type == NLMSG_DONE) { + DBG(ENDPOINTS, ul_debug(" DONE")); return; - if (h->nlmsg_type == NLMSG_ERROR) + } + if (h->nlmsg_type == NLMSG_ERROR) { + struct nlmsgerr *e = (struct nlmsgerr *)NLMSG_DATA(h); + DBG(ENDPOINTS, ul_debug(" ERROR: %s", + strerror(- e->error))); return; + } if (h->nlmsg_type == SOCK_DIAG_BY_FAMILY) { + DBG(ENDPOINTS, ul_debug(" FAMILY")); if (!cb(netns, h->nlmsg_len, NLMSG_DATA(h))) return; } + DBG(ENDPOINTS, ul_debug(" NEXT")); } + DBG(ENDPOINTS, ul_debug(" OK: 0")); } } @@ -639,6 +658,8 @@ static void load_xinfo_from_proc_unix(ino_t netns_inode) FILE *unix_fp; unix_fp = fopen("/proc/net/unix", "r"); + DBG(ENDPOINTS, ul_debug("open /proc/net/unix [fp=%p; %s]", unix_fp, + unix_fp? "successful": strerror(errno))); if (!unix_fp) return; @@ -655,13 +676,18 @@ static void load_xinfo_from_proc_unix(ino_t netns_inode) unsigned long inode; struct unix_xinfo *ux; char path[UNIX_LINE_LEN + 1] = { 0 }; + int r; + DBG(ENDPOINTS, ul_debug(" line: %s", line)); - if (sscanf(line, "%*x: %*x %*x %" SCNx64 " %x %x %lu %" + r = sscanf(line, "%*x: %*x %*x %" SCNx64 " %x %x %lu %" stringify_value(UNIX_LINE_LEN) "[^\n]", - &flags, &type, &st, &inode, path) < 4) + &flags, &type, &st, &inode, path); + DBG(ENDPOINTS, ul_debug(" scanf: %d", r)); + if (r < 4) continue; + DBG(ENDPOINTS, ul_debug(" inode: %lu", inode)); if (inode == 0) continue; @@ -675,10 +701,12 @@ static void load_xinfo_from_proc_unix(ino_t netns_inode) ux->st = st; xstrncpy(ux->path, path, sizeof(ux->path)); + DBG(ENDPOINTS, ul_debug(" path: %s", ux->path)); add_sock_info(&ux->sock); } out: + DBG(ENDPOINTS, ul_debug("close /proc/net/unix")); fclose(unix_fp); } @@ -712,6 +740,9 @@ static bool handle_diag_unix(ino_t netns __attribute__((__unused__)), if (diag->udiag_family != AF_UNIX) return false; + DBG(ENDPOINTS, ul_debug(" UNIX")); + DBG(ENDPOINTS, ul_debug(" LEN: %zu (>= %zu)", nlmsg_len, + (size_t)(NLMSG_LENGTH(sizeof(*diag))))); if (nlmsg_len < NLMSG_LENGTH(sizeof(*diag))) return false; @@ -719,21 +750,29 @@ static bool handle_diag_unix(ino_t netns __attribute__((__unused__)), inode = (ino_t)diag->udiag_ino; xinfo = get_sock_xinfo(inode); + DBG(ENDPOINTS, ul_debug(" inode: %llu", (unsigned long long)inode)); + DBG(ENDPOINTS, ul_debug(" xinfo: %p", xinfo)); + if (xinfo == NULL) /* The socket is found in the diag response but not in the proc fs. */ return true; + DBG(ENDPOINTS, ul_debug(" xinfo->class == &unix_xinfo_class: %d", + xinfo->class == &unix_xinfo_class)); if (xinfo->class != &unix_xinfo_class) return true; unix_xinfo = (struct unix_xinfo *)xinfo; rta_len = nlmsg_len - NLMSG_LENGTH(sizeof(*diag)); + DBG(ENDPOINTS, ul_debug(" rta_len: %zu", rta_len)); for (struct rtattr *attr = (struct rtattr *)(diag + 1); RTA_OK(attr, rta_len); attr = RTA_NEXT(attr, rta_len)) { size_t len = RTA_PAYLOAD(attr); + DBG(ENDPOINTS, ul_debug(" len = %2zu, type: %d", + rta_len, attr->rta_type)); switch (attr->rta_type) { case UNIX_DIAG_NAME: unix_refill_name(xinfo, RTA_DATA(attr), len); diff --git a/misc-utils/lsfd.c b/misc-utils/lsfd.c index f042f5caaa..09503d0ab7 100644 --- a/misc-utils/lsfd.c +++ b/misc-utils/lsfd.c @@ -84,6 +84,14 @@ static int kcmp(pid_t pid1 __attribute__((__unused__)), #include "lsfd.h" +UL_DEBUG_DEFINE_MASK(lsfd); +UL_DEBUG_DEFINE_MASKNAMES(lsfd) = UL_DEBUG_EMPTY_MASKNAMES; + +static void lsfd_init_debug(void) +{ + __UL_INIT_DEBUG_FROM_ENV(lsfd, LSFD_DEBUG_, 0, LSFD_DEBUG); +} + /* * /proc/$pid/mountinfo entries */ @@ -2509,6 +2517,8 @@ int main(int argc, char *argv[]) { NULL, 0, NULL, 0 }, }; + lsfd_init_debug(); + setlocale(LC_ALL, ""); bindtextdomain(PACKAGE, LOCALEDIR); textdomain(PACKAGE); diff --git a/misc-utils/lsfd.h b/misc-utils/lsfd.h index 217bf45338..f70f53cc15 100644 --- a/misc-utils/lsfd.h +++ b/misc-utils/lsfd.h @@ -28,7 +28,11 @@ #include <sys/stat.h> #include <dirent.h> #include <inttypes.h> +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include "debug.h" #include "libsmartcols.h" #include "list.h" #include "nls.h" @@ -37,6 +41,17 @@ #include "xalloc.h" /* + * debug + */ +UL_DEBUG_DECLARE_MASK(lsfd); + +#define LSFD_DEBUG_INIT (1 << 1) +#define LSFD_DEBUG_ENDPOINTS (1 << 2) +#define LSFD_DEBUG_ALL 0xFFFF + +#define DBG(m, x) __UL_DBG(lsfd, LSFD_DEBUG_, m, x) + +/* * column IDs */ enum { diff --git a/tests/helpers/test_mkfds.c b/tests/helpers/test_mkfds.c index 28ed3bffcb..60ebdd6761 100644 --- a/tests/helpers/test_mkfds.c +++ b/tests/helpers/test_mkfds.c @@ -34,6 +34,8 @@ #include <linux/if_packet.h> #include <linux/if_tun.h> #include <linux/netlink.h> +#include <linux/sock_diag.h> +# include <linux/unix_diag.h> /* for UNIX domain sockets */ #include <linux/sockios.h> /* SIOCGSKNS */ #include <mqueue.h> #include <net/if.h> @@ -69,7 +71,8 @@ #define EXIT_EPERM 18 #define EXIT_ENOPROTOOPT 19 #define EXIT_EPROTONOSUPPORT 20 -#define EXIT_EACCESS 21 +#define EXIT_EACCES 21 +#define EXIT_ENOENT 22 #define _U_ __attribute__((__unused__)) @@ -2097,7 +2100,7 @@ static void *make_ping_common(const struct factory *factory, struct fdesc fdescs sd = socket(family, SOCK_DGRAM, protocol); if (sd < 0) - err((errno == EACCES? EXIT_EACCESS: EXIT_FAILURE), + err((errno == EACCES? EXIT_EACCES: EXIT_FAILURE), "failed to make an icmp socket"); if (sd != fdescs[0].fd) { @@ -2117,7 +2120,7 @@ static void *make_ping_common(const struct factory *factory, struct fdesc fdescs int e = errno; close(sd); errno = e; - err((errno == EACCES? EXIT_EACCESS: EXIT_FAILURE), + err((errno == EACCES? EXIT_EACCES: EXIT_FAILURE), "failed in bind(2)"); } } @@ -3307,6 +3310,129 @@ static void free_mmap(const struct factory * factory _U_, void *data) ((struct mmap_data *)data)->len); } +static int send_diag_request(int diagsd, void *req, size_t req_size) +{ + struct sockaddr_nl nladdr = { + .nl_family = AF_NETLINK, + }; + + struct nlmsghdr nlh = { + .nlmsg_len = sizeof(nlh) + req_size, + .nlmsg_type = SOCK_DIAG_BY_FAMILY, + .nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP, + }; + + struct iovec iovecs[] = { + { &nlh, sizeof(nlh) }, + { req, req_size }, + }; + + const struct msghdr mhd = { + .msg_namelen = sizeof(nladdr), + .msg_name = &nladdr, + .msg_iovlen = ARRAY_SIZE(iovecs), + .msg_iov = iovecs, + }; + + if (sendmsg(diagsd, &mhd, 0) < 0) + return errno; + + return 0; +} + +static int recv_diag_request(int diagsd) +{ + __attribute__((aligned(sizeof(void *)))) uint8_t buf[8192]; + const struct nlmsghdr *h; + int r = recvfrom(diagsd, buf, sizeof(buf), 0, NULL, NULL);; + if (r < 0) + return errno; + + h = (void *)buf; + if (!NLMSG_OK(h, (size_t)r)) + return -1; + + if (h->nlmsg_type == NLMSG_ERROR) { + struct nlmsgerr *e = (struct nlmsgerr *)NLMSG_DATA(h); + return - e->error; + } + return 0; +} + +static void *make_sockdiag(const struct factory *factory, struct fdesc fdescs[], + int argc, char ** argv) +{ + struct arg family = decode_arg("family", factory->params, argc, argv); + const char *sfamily = ARG_STRING(family); + int ifamily; + int diagsd; + void *req = NULL; + size_t reqlen = 0; + int e; + struct unix_diag_req udr; + + if (strcmp(sfamily, "unix") == 0) + ifamily = AF_UNIX; + else + errx(EXIT_FAILURE, "unknown/unsupported family: %s", sfamily); + free_arg(&family); + + diagsd = socket(AF_NETLINK, SOCK_DGRAM, NETLINK_SOCK_DIAG); + if (diagsd < 0) + err(errno == EPROTONOSUPPORT? EXIT_EPROTONOSUPPORT: EXIT_FAILURE, + "failed in sendmsg()"); + + if (ifamily == AF_UNIX) { + udr = (struct unix_diag_req) { + .sdiag_family = AF_UNIX, + .udiag_states = -1, /* set the all bits. */ + .udiag_show = UDIAG_SHOW_NAME | UDIAG_SHOW_PEER | UNIX_DIAG_SHUTDOWN, + }; + req = &udr; + reqlen = sizeof(udr); + } + + e = send_diag_request(diagsd, req, reqlen); + if (e) { + close (diagsd); + errno = e; + if (errno == EACCES) + err(EXIT_EACCES, "failed in sendmsg()"); + if (errno == ENOENT) + err(EXIT_ENOENT, "failed in sendmsg()"); + err(EXIT_FAILURE, "failed in sendmsg()"); + } + + e = recv_diag_request(diagsd); + if (e != 0) { + close (diagsd); + if (e == ENOENT) + err(EXIT_ENOENT, "failed in recvfrom()"); + if (e > 0) + err(EXIT_FAILURE, "failed in recvfrom()"); + if (e < 0) + errx(EXIT_FAILURE, "failed in recvfrom() => -1"); + } + + if (diagsd != fdescs[0].fd) { + if (dup2(diagsd, fdescs[0].fd) < 0) { + e = errno; + close(diagsd); + errno = e; + err(EXIT_FAILURE, "failed to dup %d -> %d", diagsd, fdescs[0].fd); + } + close(diagsd); + } + + fdescs[0] = (struct fdesc){ + .fd = fdescs[0].fd, + .close = close_fdesc, + .data = NULL + }; + + return NULL; +} + #define PARAM_END { .name = NULL, } static const struct factory factories[] = { { @@ -4168,6 +4294,24 @@ static const struct factory factories[] = { PARAM_END } }, + { + .name = "sockdiag", + .desc = "make a sockdiag netlink socket", + .priv = false, + .N = 1, + .EX_N = 0, + .make = make_sockdiag, + .params = (struct parameter []) { + { + .name = "family", + .type = PTYPE_STRING, + /* TODO: inet, inet6 */ + .desc = "name of a protocol family ([unix])", + .defv.string = "unix", + }, + PARAM_END + } + }, }; static int count_parameters(const struct factory *factory) diff --git a/tests/ts/lsfd/lsfd-functions.bash b/tests/ts/lsfd/lsfd-functions.bash index 43c02ad704..3a3f58f0c8 100644 --- a/tests/ts/lsfd/lsfd-functions.bash +++ b/tests/ts/lsfd/lsfd-functions.bash @@ -19,7 +19,8 @@ readonly EPERM=18 readonly ENOPROTOOPT=19 readonly EPROTONOSUPPORT=20 -readonly EACCESS=21 +readonly EACCES=21 +readonly ENOENT=22 function lsfd_wait_for_pausing { ts_check_prog "sleep" @@ -58,7 +59,7 @@ function lsfd_compare_dev { fi } -lsfd_strip_type_stream() +function lsfd_strip_type_stream { # lsfd changes the output of NAME column for a unix stream socket # whether the kernel reports it is a "UNIX-STREAM" socket or a @@ -67,7 +68,7 @@ lsfd_strip_type_stream() sed -e 's/ type=stream//' } -lsfd_make_state_connected() +function lsfd_make_state_connected { # Newer kernels report the states of unix dgram sockets created by # sockerpair(2) are "connected" via /proc/net/unix though Older @@ -92,3 +93,29 @@ function lsfd_check_mkfds_factory ts_skip "test_mkfds has no factory for $FACTORY" fi } + +function lsfd_check_sockdiag +{ + local family=$1 + + ts_check_test_command "$TS_HELPER_MKFDS" + + local msg + local err + + msg=$("$TS_HELPER_MKFDS" -c sockdiag 9 family=$family 2>&1) + err=$? + + case $err in + 0) + return;; + $EPROTONOSUPPORT) + ts_skip "NETLINK_SOCK_DIAG protocol is not supported in socket(2)";; + $EACCES) + ts_skip "sending a msg via a sockdiag netlink socket is not permitted";; + $ENOENT) + ts_skip "sockdiag netlink socket is not available";; + *) + ts_failed "failed to create a sockdiag netlink socket $family ($err): $msg";; + esac +} diff --git a/tests/ts/lsfd/mkfds-ping b/tests/ts/lsfd/mkfds-ping index 21777426ae..2baafdeb4e 100755 --- a/tests/ts/lsfd/mkfds-ping +++ b/tests/ts/lsfd/mkfds-ping @@ -90,7 +90,7 @@ ERRMSG= for i in 0 1; do ERRMSG=$("$TS_HELPER_MKFDS" -c -q "${FACTORY[$i]}" 3 id=$ID 2>&1) ERR="$?" - if [[ "$ERR" == "$EACCESS" ]]; then + if [[ "$ERR" == "$EACCES" ]]; then case "$ERRMSG" in *bind*) MSG="making ${TYPE[$i]} socket with specifying id is not allowed (blocked by SELinux?)" diff --git a/tests/ts/lsfd/mkfds-socketpair b/tests/ts/lsfd/mkfds-socketpair index 38f9279ceb..3ef60c79e4 100755 --- a/tests/ts/lsfd/mkfds-socketpair +++ b/tests/ts/lsfd/mkfds-socketpair @@ -20,6 +20,7 @@ TS_DESC="AF_UNIX socket pair created with socketpair(2)" . "$TS_TOPDIR"/functions.sh ts_init "$*" +. "$TS_SELF/lsfd-functions.bash" ts_check_test_command "$TS_CMD_LSFD" ts_check_test_command "$TS_HELPER_MKFDS" @@ -28,6 +29,8 @@ ts_check_prog "sed" ts_cd "$TS_OUTDIR" +lsfd_check_sockdiag "unix" + PID= FD0=3 FD1=4 diff --git a/tests/ts/lsfd/mkfds-unix-stream-requiring-sockdiag b/tests/ts/lsfd/mkfds-unix-stream-requiring-sockdiag index c188464b2c..6189d0db46 100755 --- a/tests/ts/lsfd/mkfds-unix-stream-requiring-sockdiag +++ b/tests/ts/lsfd/mkfds-unix-stream-requiring-sockdiag @@ -28,6 +28,8 @@ ts_check_test_command "$TS_HELPER_MKFDS" ts_cd "$TS_OUTDIR" +lsfd_check_sockdiag "unix" + PID= FDS=3 FDC=4 |