From nobody Mon Sep 16 19:51:09 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zohomail.com: domain of redhat.com designates 170.10.133.124 as permitted sender) client-ip=170.10.133.124; envelope-from=libvir-list-bounces@redhat.com; helo=us-smtp-delivery-124.mimecast.com; Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of redhat.com designates 170.10.133.124 as permitted sender) smtp.mailfrom=libvir-list-bounces@redhat.com; dmarc=pass(p=none dis=none) header.from=redhat.com ARC-Seal: i=1; a=rsa-sha256; t=1682911446; cv=none; d=zohomail.com; s=zohoarc; b=TXXzOxTtoa5uAaa+nIRhKgr745uiOK0+bbKyL4GyZkwJkyeV5LOYn+5XytJiJh6gnwTCDiK3I8twFN06K09xBZw048G1voQwQEjQM+42vvh8iZC9hM832SebpNfPByhRbRQBLCxIwo2QjUA64nr5a9L6tBDtGhA1IDX2Ya5tc1s= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1682911446; h=Content-Type:Content-Transfer-Encoding:Date:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:To; bh=AB3E3/e+XDQMyWxIUhOIRLBH8clQwMxKGfYHzRt7T1I=; b=NfK76NmNoxi+rUSrVGuqBa9JyVGRKy5LxAQObo945ZmrKe2dvvFNyL5qt4eVKD7+xw4N35F8qjm7W1Qb6c6daqkWASYz9ARX8nraAQkwT5GBI8nEEbELs9U073yRzfvZ4GyXoG/NsQU0N0KkxWKFZ7e3dXwq146xY5eKKzFuWqU= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of redhat.com designates 170.10.133.124 as permitted sender) smtp.mailfrom=libvir-list-bounces@redhat.com; dmarc=pass header.from= (p=none dis=none) Return-Path: Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) by mx.zohomail.com with SMTPS id 1682911446499895.7909124342485; Sun, 30 Apr 2023 20:24:06 -0700 (PDT) Received: from mimecast-mx02.redhat.com (mimecast-mx02.redhat.com [66.187.233.88]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-616-xWnLH4rVOfiLb228zr4bSA-1; Sun, 30 Apr 2023 23:20:30 -0400 Received: from smtp.corp.redhat.com (int-mx06.intmail.prod.int.rdu2.redhat.com [10.11.54.6]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id 177E2858297; Mon, 1 May 2023 03:20:17 +0000 (UTC) Received: from mm-prod-listman-01.mail-001.prod.us-east-1.aws.redhat.com (mm-prod-listman-01.mail-001.prod.us-east-1.aws.redhat.com [10.30.29.100]) by smtp.corp.redhat.com (Postfix) with ESMTP id E845D2166B2E; Mon, 1 May 2023 03:20:16 +0000 (UTC) Received: from mm-prod-listman-01.mail-001.prod.us-east-1.aws.redhat.com (localhost [IPv6:::1]) by mm-prod-listman-01.mail-001.prod.us-east-1.aws.redhat.com (Postfix) with ESMTP id 21BC219459FC; Mon, 1 May 2023 03:20:09 +0000 (UTC) Received: from smtp.corp.redhat.com (int-mx10.intmail.prod.int.rdu2.redhat.com [10.11.54.10]) by mm-prod-listman-01.mail-001.prod.us-east-1.aws.redhat.com (Postfix) with ESMTP id D4CD31946588 for ; Mon, 1 May 2023 03:20:05 +0000 (UTC) Received: by smtp.corp.redhat.com (Postfix) id 5CECF475023; Mon, 1 May 2023 03:19:47 +0000 (UTC) Received: from vhost3.router.laine.org (unknown [10.22.8.105]) by smtp.corp.redhat.com (Postfix) with ESMTP id 43903475022 for ; Mon, 1 May 2023 03:19:47 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1682911445; h=from:from:sender:sender: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: in-reply-to:in-reply-to:references:references:list-id:list-help: list-unsubscribe:list-subscribe:list-post; bh=AB3E3/e+XDQMyWxIUhOIRLBH8clQwMxKGfYHzRt7T1I=; b=fz25HczJ2yWLKlQxruy1YSCZYHfWYoDRgyusz4T7CBxptREeoGomdk+b0mmf5fVW1vaOCR IMv8iVtpr2zaQyrsPQymADVkrzREXDVlcLKHUveJK93MHOY8iE2R16STjhdcS+iy4zL1Qo w5tnfMmQiYZxmeG64ByxbrAYGJwrIVU= X-MC-Unique: xWnLH4rVOfiLb228zr4bSA-1 X-Original-To: libvir-list@listman.corp.redhat.com From: Laine Stump To: libvir-list@redhat.com Subject: [libvirt PATCH 21/28] util: implement rollback rule autosave for nftables backend Date: Sun, 30 Apr 2023 23:19:36 -0400 Message-Id: <20230501031943.288145-22-laine@redhat.com> In-Reply-To: <20230501031943.288145-1-laine@redhat.com> References: <20230501031943.288145-1-laine@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.1 on 10.11.54.10 X-BeenThere: libvir-list@redhat.com X-Mailman-Version: 2.1.29 Precedence: list List-Id: Development discussions about the libvirt library & tools List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: libvir-list-bounces@redhat.com Sender: "libvir-list" X-Scanned-By: MIMEDefang 3.1 on 10.11.54.6 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Content-Transfer-Encoding: quoted-printable X-ZohoMail-DKIM: pass (identity @redhat.com) X-ZM-MESSAGEID: 1682911448547100001 Content-Type: text/plain; charset="utf-8"; x-default="true" Determining the correct rollback rule for nftables is more complicated than iptables - nftables give each new table/chain/rule a handle, and the nft delete command to delete the object must contain that handle (rather than just replicating the entire original commandline as is done for iptables). The handle is obtained by adding an extra "-ae" option to the original nft commandline, and then parsing stdout of the command looking for "# handle n" (where "n" is a decimal integer). This code isn't yet used anywhere, since VIR_FIREWALL_TRANSACTION_AUTO_ROLLBACK isn't being set. Signed-off-by: Laine Stump --- src/util/virnftables.c | 106 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 105 insertions(+), 1 deletion(-) diff --git a/src/util/virnftables.c b/src/util/virnftables.c index b43b14bb82..0cc09caaed 100644 --- a/src/util/virnftables.c +++ b/src/util/virnftables.c @@ -71,12 +71,18 @@ VIR_ENUM_IMPL(virNftablesAction, ); =20 =20 +#define VIR_ARG_IS_INSERT(arg) \ + (STREQ(arg, "insert") || STREQ(arg, "add") || STREQ(arg, "create")) + int virNftablesApplyFirewallRule(virFirewall *firewall G_GNUC_UNUSED, virFirewallRule *rule, char **output) { size_t count =3D virFirewallRuleGetArgCount(rule); + bool needRollback =3D false; + size_t cmdIdx =3D 0; + const char *objectType =3D NULL; g_autoptr(virCommand) cmd =3D NULL; g_autofree char *cmdStr =3D NULL; g_autofree char *error =3D NULL; @@ -91,11 +97,45 @@ virNftablesApplyFirewallRule(virFirewall *firewall G_GN= UC_UNUSED, =20 cmd =3D virCommandNew(NFT); =20 + if ((virFirewallTransactionGetFlags(firewall) + & VIR_FIREWALL_TRANSACTION_AUTO_ROLLBACK) + && count > 1) { + /* skip any leading options to get to command verb */ + for (i =3D 0; i < count - 1; i++) { + if (virFirewallRuleGetArg(rule, i)[0] !=3D '-') + break; + } + + if (i + 1 < count + && VIR_ARG_IS_INSERT(virFirewallRuleGetArg(rule, i))) { + + cmdIdx =3D i; + objectType =3D virFirewallRuleGetArg(rule, i + 1); + + /* we currently only handle auto-rollback for rules, + * chains, and tables, and those all can be "rolled + * back" by a delete command using the handle that is + * returned when "-ae" is added to the add/insert + * command. + */ + if (STREQ_NULLABLE(objectType, "rule") + || STREQ_NULLABLE(objectType, "chain") + || STREQ_NULLABLE(objectType, "table")) { + + needRollback =3D true; + /* this option to nft instructs it to add the + * "handle" of the created object to stdout + */ + virCommandAddArg(cmd, "-ae"); + } + } + } + for (i =3D 0; i < count; i++) virCommandAddArg(cmd, virFirewallRuleGetArg(rule, i)); =20 cmdStr =3D virCommandToString(cmd, false); - VIR_INFO("Applying rule '%s'", NULLSTR(cmdStr)); + VIR_INFO("Applying '%s'", NULLSTR(cmdStr)); =20 virCommandSetOutputBuffer(cmd, output); virCommandSetErrorBuffer(cmd, &error); @@ -118,8 +158,72 @@ virNftablesApplyFirewallRule(virFirewall *firewall G_G= NUC_UNUSED, VIR_FREE(*output); return -1; } + + /* there was an error, so we won't be building any rollback rule, + * but the error should be ignored, so we return success + */ + return 0; } =20 + if (needRollback) { + virFirewallRule *rollback + =3D virFirewallAddRollbackRule(firewall, + virFirewallRuleGetLayer(rule), NU= LL); + const char *handleStart =3D NULL; + size_t handleLen =3D 0; + g_autofree char *handleStr =3D NULL; + g_autofree char *rollbackStr =3D NULL; + + /* Search for "# handle n" in stdout of the nft add command - + * that is the handle of the table/rule/chain that will later + * need to be deleted. + */ + + if ((handleStart =3D strstr(*output, "# handle "))) { + handleStart +=3D 9; /* move past "# handle " */ + handleLen =3D strspn(handleStart, "0123456789"); + } + + if (!handleLen) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("couldn't register rollback command - command= '%1$s' had no valid handle in output ('%2$s')"), + NULLSTR(cmdStr), NULLSTR(*output)); + return -1; + } + + handleStr =3D g_strdup_printf("%.*s", (int)handleLen, handleStart); + + /* The rollback rule is created from the original rule like this: + * + * 1) skip any leading options + * 2) replace add/insert with delete + * 3) keep the type of item being added (rule/chain/table) + * 4) keep the class (ip/ip6/inet) + * 5) for chain/rule, keep the table name + * 6) for rule, keep the chain name + * 7) add "handle n" where "n" is parsed from the + * stdout of the nft command + */ + virFirewallRuleAddArgList(firewall, rollback, "delete", objectType, + virFirewallRuleGetArg(rule, cmdIdx + 2),= /* ip/ip6/inet */ + NULL); + + if (STREQ_NULLABLE(objectType, "rule") + || STREQ_NULLABLE(objectType, "chain")) { + /* include table name in command */ + virFirewallRuleAddArg(firewall, rollback, + virFirewallRuleGetArg(rule, cmdIdx + 3)); + } + if (STREQ_NULLABLE(objectType, "rule")) { + /* include chain name in command */ + virFirewallRuleAddArg(firewall, rollback, + virFirewallRuleGetArg(rule, cmdIdx + 4)); + } + virFirewallRuleAddArgList(firewall, rollback, "handle", handleStr,= NULL); + + rollbackStr =3D virFirewallRuleToString(NFT, rollback); + VIR_DEBUG("Recording Rollback command '%s'", NULLSTR(rollbackStr)); + } return 0; } =20 --=20 2.39.2