aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMasatake YAMATO <yamato@redhat.com>2024-03-16 22:07:43 +0900
committerMasatake YAMATO <yamato@redhat.com>2024-04-05 18:31:14 +0900
commit6979e2a111ad0e1383b4b239042b12d35cd99ff6 (patch)
tree22f373c9db2a8939ad7c66103a8123a163557618
parent5f77e0ffe653b82378d24da26979cd7493e45542 (diff)
downloadutil-linux-6979e2a111ad0e1383b4b239042b12d35cd99ff6.tar.gz
tests: (test_mkfds::sockdiag) new factory
The factory is for detecting whether a platform provides NETLINK_SOCK_DIAG sockets for a given family. Signed-off-by: Masatake YAMATO <yamato@redhat.com>
-rw-r--r--tests/helpers/test_mkfds.c115
-rw-r--r--tests/ts/lsfd/lsfd-functions.bash27
2 files changed, 142 insertions, 0 deletions
diff --git a/tests/helpers/test_mkfds.c b/tests/helpers/test_mkfds.c
index bbce228fd5..15e9016963 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>
@@ -70,6 +72,7 @@
#define EXIT_ENOPROTOOPT 19
#define EXIT_EPROTONOSUPPORT 20
#define EXIT_EACCES 21
+#define EXIT_ENOENT 22
#define _U_ __attribute__((__unused__))
@@ -3307,6 +3310,100 @@ 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 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()");
+ }
+
+
+ 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 +4265,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 d7eab146a7..3a3f58f0c8 100644
--- a/tests/ts/lsfd/lsfd-functions.bash
+++ b/tests/ts/lsfd/lsfd-functions.bash
@@ -20,6 +20,7 @@ readonly EPERM=18
readonly ENOPROTOOPT=19
readonly EPROTONOSUPPORT=20
readonly EACCES=21
+readonly ENOENT=22
function lsfd_wait_for_pausing {
ts_check_prog "sleep"
@@ -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
+}