git: e26d1cea25cd - main - ipfw: add IPv6 logging via rtsock support for fwd tablearg opcode

From: Andrey V. Elsukov <ae_at_FreeBSD.org>
Date: Fri, 18 Apr 2025 12:34:18 UTC
The branch main has been updated by ae:

URL: https://cgit.FreeBSD.org/src/commit/?id=e26d1cea25cd4d2ce95032022f7823b012c58c5f

commit e26d1cea25cd4d2ce95032022f7823b012c58c5f
Author:     Andrey V. Elsukov <ae@FreeBSD.org>
AuthorDate: 2025-04-18 11:48:25 +0000
Commit:     Andrey V. Elsukov <ae@FreeBSD.org>
CommitDate: 2025-04-18 11:48:25 +0000

    ipfw: add IPv6 logging via rtsock support for fwd tablearg opcode
    
    Also fix handling for O_SETMARK opcode. O_MARK should not be handled
    together with action opcodes.
    
    Obtained from:  Yandex LLC
    Sponsored by:   Yandex LLC
---
 sys/netpfil/ipfw/ip_fw_log.c | 52 ++++++++++++++++++++++++++++++--------------
 1 file changed, 36 insertions(+), 16 deletions(-)

diff --git a/sys/netpfil/ipfw/ip_fw_log.c b/sys/netpfil/ipfw/ip_fw_log.c
index 3f3980b8ee65..98b7a758c612 100644
--- a/sys/netpfil/ipfw/ip_fw_log.c
+++ b/sys/netpfil/ipfw/ip_fw_log.c
@@ -506,11 +506,10 @@ ipfw_rtsocklog_fill_l3(struct ip_fw_args *args,
 }
 
 static struct sockaddr *
-ipfw_rtsocklog_handle_tablearg(struct ip_fw_chain *chain, ipfw_insn *cmd,
-    uint32_t tablearg, uint32_t *targ_value, char **buf)
+ipfw_rtsocklog_handle_tablearg(struct ip_fw_chain *chain,
+    struct ip_fw_args *args, ipfw_insn *cmd, uint32_t tablearg,
+    uint32_t *targ_value, char **buf)
 {
-	struct sockaddr_in *v4nh = NULL;
-
 	/* handle tablearg now */
 	switch (cmd->opcode) {
 	case O_DIVERT:
@@ -531,26 +530,47 @@ ipfw_rtsocklog_handle_tablearg(struct ip_fw_chain *chain, ipfw_insn *cmd,
 	case O_CALLRETURN:
 		if (cmd->opcode == O_CALLRETURN && (cmd->len & F_NOT))
 			break;
-		*targ_value = (TARG(insntod(cmd, u32)->d[0], skipto));
+		*targ_value = TARG(insntod(cmd, u32)->d[0], skipto);
 		break;
 	case O_PIPE:
 	case O_QUEUE:
 		*targ_value = TARG(cmd->arg1, pipe);
 		break;
-	case O_MARK:
-		*targ_value = TARG(cmd->arg1, mark);
+	case O_SETMARK:
+		if (cmd->arg1 == IP_FW_TARG)
+			*targ_value = TARG_VAL(chain, tablearg, mark);
 		break;
 	case O_FORWARD_IP:
-		v4nh = (struct sockaddr_in *)buf;
-		buf += sizeof(*v4nh);
-		*v4nh = ((ipfw_insn_sa *)cmd)->sa;
-		if (v4nh->sin_addr.s_addr == INADDR_ANY)
-			v4nh->sin_addr.s_addr = htonl(tablearg);
-
-		return (struct sockaddr *)v4nh;
+		if (IS_IP4_FLOW_ID(&args->f_id)) {
+			struct sockaddr_in *nh = (struct sockaddr_in *)*buf;
+
+			*buf += sizeof(*nh);
+			memcpy(nh, &insntod(cmd, sa)->sa, sizeof(*nh));
+			if (nh->sin_addr.s_addr == INADDR_ANY)
+				nh->sin_addr.s_addr = htonl(
+				    TARG_VAL(chain, tablearg, nh4));
+			return ((struct sockaddr *)nh);
+		}
+		/* FALLTHROUGH */
 #ifdef INET6
 	case O_FORWARD_IP6:
-		return (struct sockaddr *)&(((ipfw_insn_sa6 *)cmd)->sa);
+		if (IS_IP6_FLOW_ID(&args->f_id)) {
+			const struct sockaddr_in *sin = &insntod(cmd, sa)->sa;
+			struct sockaddr_in6 *nh = (struct sockaddr_in6 *)*buf;
+
+			*buf += sizeof(*nh);
+			if (cmd->opcode == O_FORWARD_IP &&
+			    sin->sin_addr.s_addr == INADDR_ANY) {
+				nh->sin6_family = AF_INET6;
+				nh->sin6_len = sizeof(*nh);
+				nh->sin6_addr = TARG_VAL(chain, tablearg, nh6);
+				nh->sin6_port = sin->sin_port;
+				nh->sin6_scope_id =
+				    TARG_VAL(chain, tablearg, zoneid);
+			} else
+				memcpy(nh, &insntod(cmd, sa6)->sa, sizeof(*nh));
+			return ((struct sockaddr *)nh);
+		}
 #endif
 	default:
 		break;
@@ -661,7 +681,7 @@ ipfw_log_rtsock(struct ip_fw_chain *chain, struct ip_fw *f, u_int hlen,
 
 	/* handle tablearg */
 	info->rti_info[RTAX_GENMASK] = ipfw_rtsocklog_handle_tablearg(
-	    chain, cmd, tablearg, targ_value, &buf);
+	    chain, args, cmd, tablearg, targ_value, &buf);
 
 	/* L3 */
 	ipfw_rtsocklog_fill_l3(args, &buf,