From nobody Sat Feb 01 09:02:06 2025 X-Original-To: dev-commits-src-main@mlmmj.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mlmmj.nyi.freebsd.org (Postfix) with ESMTP id 4YlRbM1Fzqz5mbVW; Sat, 01 Feb 2025 09:02:07 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256 client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "R11" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 4YlRbL6JG0z410h; Sat, 01 Feb 2025 09:02:06 +0000 (UTC) (envelope-from git@FreeBSD.org) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1738400526; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=61TRwwHcCvDKiS+V+MfkH9IHaimFFA0CiX7m08JRP18=; b=xf4OZjeASj88kIyk1ohUR/W+8/wp7rXApI7pZ1zMGNc2wwIb5Pwf4Du33PU+KMwmdGfH76 KbO8rUVvth1HaWG+9SjLqB5qPupx7qPgaLp8d73x20oA0S3qX7uphqWZZzWQgOomW0bWpa NqhJKu1sH1Nm6KGri+t5+XxEgx17fD5AShD4uCobn/WIbiVc2EUgKmmLl44LnXdBp48/9B 8xV5onhN5IxbQXfrAmhrBNKIVXVp2vXj9N13q8GGS1A/dNaXeK56TZ49N9xOGp111aJr5T mYLVScrKrAKUvFqX4K6H7wv4EzhcvEAZYuNGEbejG2Bnngb7x8YiP6FiOlgqmQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1738400526; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=61TRwwHcCvDKiS+V+MfkH9IHaimFFA0CiX7m08JRP18=; b=eCYWQSBebgLLblLHwcl9k1lv+7X7UbT0bP+HcvOLYGiR2FUSBwY97FNpL++/DN5H1TBiUp EmeCCtxS/JJmhGhvPVHY8OKhSRqOn8jFXM71xs2+kkp84E7AcOXjrdQTrZjxyh8QeVXPaR RncA+Ot42uhrVowUYtqoKzIdeqX1cW0PpSj/tlSdprrb3PYuVG/welwzDlznU0Sfkm36Kb q6s24/ISV/EjMs8SrJm0J/TDGoYzpBsw2BBZN4e8fiqf9AMv6aL7UWQ9ZEFaJMloLxtGIg rFWktCwSdJtPOZufXH+ipQ1/NmFyX3jSoPmch5AiglojFROvwvOSvOq8Akd4gg== ARC-Seal: i=1; s=dkim; d=freebsd.org; t=1738400526; a=rsa-sha256; cv=none; b=sFVE7lDwoYcNUj0oVuqhAaBtHNj0vDcjoIWUq7G1+DjHPsqo6bdGrAU2iU9PQjRyXa+sH2 zBQzVwbu4jwp/XbcmI1n1iRpRBitZ5yGHVGOvNSIg6oJX4FWrHs57znQOJGk38CxzLjIaN PLY42lui3/9RGlvO9EV3m0JzIdf/kFkA01cIcLEg4WZSPMO7Cobd59u+qE6iVX0HhC39m8 AufXCB3KZSXB4EaHYylqC/zGkCPNl7Ey6edgpazBpX4g7hbcM2EF9rP+amQaaRAD9A9+nD OtmIDzierEWvNX23uzOx3OSXKl7NEQidAZk0qVkmgFJAmQCUHB0MPXiY4+MjqQ== ARC-Authentication-Results: i=1; mx1.freebsd.org; none Received: from gitrepo.freebsd.org (gitrepo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:5]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (Client did not present a certificate) by mxrelay.nyi.freebsd.org (Postfix) with ESMTPS id 4YlRbL590jzxHl; Sat, 01 Feb 2025 09:02:06 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from gitrepo.freebsd.org ([127.0.1.44]) by gitrepo.freebsd.org (8.18.1/8.18.1) with ESMTP id 511926GI047862; Sat, 1 Feb 2025 09:02:06 GMT (envelope-from git@gitrepo.freebsd.org) Received: (from git@localhost) by gitrepo.freebsd.org (8.18.1/8.18.1/Submit) id 511926ao047859; Sat, 1 Feb 2025 09:02:06 GMT (envelope-from git) Date: Sat, 1 Feb 2025 09:02:06 GMT Message-Id: <202502010902.511926ao047859@gitrepo.freebsd.org> To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org From: Gleb Smirnoff Subject: git: 88cd1e17a7d8 - main - genl: add RPC parser that dumps what sys/rpc/clnt_nl.c sends List-Id: Commit messages for the main branch of the src repository List-Archive: https://lists.freebsd.org/archives/dev-commits-src-main List-Help: List-Post: List-Subscribe: List-Unsubscribe: X-BeenThere: dev-commits-src-main@freebsd.org Sender: owner-dev-commits-src-main@FreeBSD.org MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit X-Git-Committer: glebius X-Git-Repository: src X-Git-Refname: refs/heads/main X-Git-Reftype: branch X-Git-Commit: 88cd1e17a7d8ba66eb5fb04441dd9264d48708b1 Auto-Submitted: auto-generated The branch main has been updated by glebius: URL: https://cgit.FreeBSD.org/src/commit/?id=88cd1e17a7d8ba66eb5fb04441dd9264d48708b1 commit 88cd1e17a7d8ba66eb5fb04441dd9264d48708b1 Author: Gleb Smirnoff AuthorDate: 2025-02-01 01:02:04 +0000 Commit: Gleb Smirnoff CommitDate: 2025-02-01 09:00:25 +0000 genl: add RPC parser that dumps what sys/rpc/clnt_nl.c sends Use a separate file for the RPC parser. Potentially it may get bigger. Also to avoid include RPC header pollution of the genl.c. Reviewed by: rmacklem Differential Revision: https://reviews.freebsd.org/D48551 --- usr.bin/genl/Makefile | 1 + usr.bin/genl/genl.c | 33 +++++++--- usr.bin/genl/genl.h | 31 +++++++++ usr.bin/genl/parser_rpc.c | 161 ++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 216 insertions(+), 10 deletions(-) diff --git a/usr.bin/genl/Makefile b/usr.bin/genl/Makefile index 15e60300de02..8ab5919b1486 100644 --- a/usr.bin/genl/Makefile +++ b/usr.bin/genl/Makefile @@ -1,3 +1,4 @@ PROG= genl +SRCS= genl.c parser_rpc.c .include diff --git a/usr.bin/genl/genl.c b/usr.bin/genl/genl.c index cb01c6bcdd26..51d2dfaa6364 100644 --- a/usr.bin/genl/genl.c +++ b/usr.bin/genl/genl.c @@ -42,11 +42,10 @@ #include #include +#include "genl.h" + static int monitor_mcast(int argc, char **argv); static int list_families(int argc, char **argv); -static void parser_nlctrl_notify(struct snl_state *ss, struct nlmsghdr *hdr); -static void parser_nlsysevent(struct snl_state *ss, struct nlmsghdr *hdr); -static void parser_fallback(struct snl_state *ss, struct nlmsghdr *hdr); static struct commands { const char *name; @@ -57,12 +56,16 @@ static struct commands { { "list", "list", list_families }, }; +static monitor_parser_t parser_nlctrl_notify; +static monitor_parser_t parser_nlsysevent; + static struct mcast_parsers { const char *family; - void (*parser)(struct snl_state *ss, struct nlmsghdr *hdr); + monitor_parser_t *parser; } mcast_parsers [] = { { "nlctrl", parser_nlctrl_notify }, { "nlsysevent", parser_nlsysevent }, + { "rpc", parser_rpc }, }; struct nlevent { @@ -252,7 +255,7 @@ dump_family(struct genl_family *family) dump_mcast_groups(&family->mcast_groups); } -void +static void parser_nlctrl_notify(struct snl_state *ss, struct nlmsghdr *hdr) { struct genl_family family = {}; @@ -262,7 +265,7 @@ parser_nlctrl_notify(struct snl_state *ss, struct nlmsghdr *hdr) dump_family(&family); } -void +static void parser_nlsysevent(struct snl_state *ss, struct nlmsghdr *hdr) { struct nlevent ne = {}; @@ -276,15 +279,25 @@ parser_nlsysevent(struct snl_state *ss, struct nlmsghdr *hdr) } } -void -parser_fallback(struct snl_state *ss __unused, struct nlmsghdr *hdr __unused) +static void +parser_fallback(struct snl_state *ss __unused, struct nlmsghdr *hdr) { - printf("New unknown message\n"); + printf("Unknown message: type 0x%x, length %u\n", + hdr->nlmsg_type, hdr->nlmsg_len); } /* Populated by monitor_mcast() and may be used by protocol parser callbacks. */ static struct genl_family attrs; +const char * +group_name(uint32_t id) +{ + for (u_int i = 0; i < attrs.mcast_groups.num_groups; i++) + if (attrs.mcast_groups.groups[i]->id == id) + return (attrs.mcast_groups.groups[i]->name); + return ("???"); +} + static int monitor_mcast(int argc, char **argv) { @@ -294,7 +307,7 @@ monitor_mcast(int argc, char **argv) struct pollfd pfd; bool found = false; bool all = false; - void (*parser)(struct snl_state *ss, struct nlmsghdr *hdr); + monitor_parser_t *parser; if (argc < 1 || argc > 2) { usage(); diff --git a/usr.bin/genl/genl.h b/usr.bin/genl/genl.h new file mode 100644 index 000000000000..7c518245440c --- /dev/null +++ b/usr.bin/genl/genl.h @@ -0,0 +1,31 @@ +/* + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright 2025 Gleb Smirnoff + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted providing that the following conditions~ + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +extern const char * group_name(uint32_t id); + +typedef void monitor_parser_t(struct snl_state *, struct nlmsghdr *); +extern monitor_parser_t parser_rpc; diff --git a/usr.bin/genl/parser_rpc.c b/usr.bin/genl/parser_rpc.c new file mode 100644 index 000000000000..d63d1425c811 --- /dev/null +++ b/usr.bin/genl/parser_rpc.c @@ -0,0 +1,161 @@ +/* + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright 2025 Gleb Smirnoff + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted providing that the following conditions~ + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include + +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "genl.h" + +struct nl_request_parsed { + uint32_t group; + struct nlattr *data; +}; +static const struct snl_attr_parser rpcnl_attr_parser[] = { +#define OUT(field) offsetof(struct nl_request_parsed, field) + { .type = RPCNL_REQUEST_GROUP, .off = OUT(group), + .cb = snl_attr_get_uint32 }, + { .type = RPCNL_REQUEST_BODY, .off = OUT(data), .cb = snl_attr_get_nla }, +#undef OUT +}; +SNL_DECLARE_PARSER(request_parser, struct genlmsghdr, snl_f_p_empty, + rpcnl_attr_parser); + +void +parser_rpc(struct snl_state *ss __unused, struct nlmsghdr *hdr) +{ + struct nl_request_parsed req; + struct genlmsghdr *ghdr = (struct genlmsghdr *)(hdr + 1); + XDR xdrs; + struct rpc_msg msg; + struct opaque_auth *oa; + int32_t *buf; + + if (!snl_parse_nlmsg(NULL, hdr, &request_parser, &req)) + errx(EXIT_FAILURE, "failed to parse RPC message"); + + printf("RPC %s: group %8s[0x%2x] length %4u XDR length %4u\n", + ghdr->cmd == RPCNL_REQUEST ? "request" : "unknown", + group_name(req.group), req.group, + hdr->nlmsg_len, NLA_DATA_LEN(req.data)); + + xdrmem_create(&xdrs, NLA_DATA(req.data), NLA_DATA_LEN(req.data), + XDR_DECODE); + if ((buf = XDR_INLINE(&xdrs, 8 * BYTES_PER_XDR_UNIT)) == NULL) { + printf("\trunt datagram\n"); + return; + } + + msg.rm_xid = IXDR_GET_U_INT32(buf); + msg.rm_direction = IXDR_GET_ENUM(buf, enum msg_type); + msg.rm_call.cb_rpcvers = IXDR_GET_U_INT32(buf); + msg.rm_call.cb_prog = IXDR_GET_U_INT32(buf); + msg.rm_call.cb_vers = IXDR_GET_U_INT32(buf); + msg.rm_call.cb_proc = IXDR_GET_U_INT32(buf); + printf(" %5s: xid 0x%-8x program 0x%08xv%u procedure %u\n", + msg.rm_direction == CALL ? "CALL" : "REPLY", msg.rm_xid, + msg.rm_call.cb_prog, msg.rm_call.cb_vers, msg.rm_call.cb_proc); + + oa = &msg.rm_call.cb_cred; + oa->oa_flavor = IXDR_GET_ENUM(buf, enum_t); + oa->oa_length = (u_int)IXDR_GET_U_INT32(buf); + if (oa->oa_length) { + printf("\tcb_cred auth flavor %u length %u\n", + oa->oa_flavor, oa->oa_length); +/* + * Excerpt from rpc_callmsg.c, if we want to parse cb_cred better. + if (oa->oa_length > MAX_AUTH_BYTES) { + return (FALSE); + } + if (oa->oa_base == NULL) { + oa->oa_base = (caddr_t) + mem_alloc(oa->oa_length); + if (oa->oa_base == NULL) + return (FALSE); + } + buf = XDR_INLINE(&xdrs, RNDUP(oa->oa_length)); + if (buf == NULL) { + if (xdr_opaque(&xdrs, oa->oa_base, + oa->oa_length) == FALSE) { + return (FALSE); + } + } else { + memmove(oa->oa_base, buf, + oa->oa_length); + } +*/ + } + oa = &msg.rm_call.cb_verf; + buf = XDR_INLINE(&xdrs, 2 * BYTES_PER_XDR_UNIT); + if (buf == NULL) { + if (xdr_enum(&xdrs, &oa->oa_flavor) == FALSE || + xdr_u_int(&xdrs, &oa->oa_length) == FALSE) + return; + } else { + oa->oa_flavor = IXDR_GET_ENUM(buf, enum_t); + oa->oa_length = (u_int)IXDR_GET_U_INT32(buf); + } + if (oa->oa_length) { + printf("\tcb_verf auth flavor %u length %u\n", + oa->oa_flavor, oa->oa_length); +/* + * Excerpt from rpc_callmsg.c, if we want to parse cb_verf better. + if (oa->oa_length > MAX_AUTH_BYTES) { + return (FALSE); + } + if (oa->oa_base == NULL) { + oa->oa_base = (caddr_t) + mem_alloc(oa->oa_length); + if (oa->oa_base == NULL) + return (FALSE); + } + buf = XDR_INLINE(&xdrs, RNDUP(oa->oa_length)); + if (buf == NULL) { + if (xdr_opaque(&xdrs, oa->oa_base, + oa->oa_length) == FALSE) { + return (FALSE); + } + } else { + memmove(oa->oa_base, buf, + oa->oa_length); + } +*/ + } +}