From nobody Thu Sep 19 01:00:32 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zohomail.com: domain of lists.libvirt.org designates 8.43.85.245 as permitted sender) client-ip=8.43.85.245; envelope-from=devel-bounces@lists.libvirt.org; helo=lists.libvirt.org; Authentication-Results: mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of lists.libvirt.org designates 8.43.85.245 as permitted sender) smtp.mailfrom=devel-bounces@lists.libvirt.org; dmarc=fail(p=none dis=none) header.from=redhat.com Return-Path: Received: from lists.libvirt.org (lists.libvirt.org [8.43.85.245]) by mx.zohomail.com with SMTPS id 1715968211391203.8863560578443; Fri, 17 May 2024 10:50:11 -0700 (PDT) Received: by lists.libvirt.org (Postfix, from userid 996) id 49564449; Fri, 17 May 2024 13:50:10 -0400 (EDT) Received: from lists.libvirt.org (localhost [IPv6:::1]) by lists.libvirt.org (Postfix) with ESMTP id 643C41C7C; Fri, 17 May 2024 13:31:18 -0400 (EDT) Received: by lists.libvirt.org (Postfix, from userid 996) id C22111A43; Fri, 17 May 2024 13:30:18 -0400 (EDT) Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by lists.libvirt.org (Postfix) with ESMTPS id C7AB119C6 for ; Fri, 17 May 2024 13:30:11 -0400 (EDT) Received: from mimecast-mx02.redhat.com (mimecast-mx02.redhat.com [66.187.233.88]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-184-MlaYF3UGOx6deQkXqWLQWg-1; Fri, 17 May 2024 13:30:09 -0400 Received: from smtp.corp.redhat.com (int-mx02.intmail.prod.int.rdu2.redhat.com [10.11.54.2]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id A7924800CB1 for ; Fri, 17 May 2024 17:30:09 +0000 (UTC) Received: from vhost3.router.laine.org (unknown [10.22.16.223]) by smtp.corp.redhat.com (Postfix) with ESMTP id 8EBB040C6CB4 for ; Fri, 17 May 2024 17:30:09 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) on lists.libvirt.org X-Spam-Level: X-Spam-Status: No, score=-0.5 required=5.0 tests=DKIM_INVALID,DKIM_SIGNED, HEADER_FROM_DIFFERENT_DOMAINS,MAILING_LIST_MULTI,RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H4,RCVD_IN_MSPIKE_WL,SPF_HELO_NONE autolearn=unavailable autolearn_force=no version=3.4.4 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1715967011; 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: in-reply-to:in-reply-to:references:references; bh=wDGeLVAbtd3WumGB5cFgVgx3YZDmfLvKa60ek82AYi8=; b=ijxIdR1QH+ozGq97bAN28fTgyMqFCrZ0TmomV8GPbEBesigUxItmv5iUOBDBJA0pc3Clg1 SQ+uSKsK9qjtcat+z+InarbCTLHDwnVEV3O/5hdxr3+GA63rh1yIyWZYWbiyKJLHGGxDiE 3wHMyWqLLLnQtVbI3JdJ75pufqbtx+k= X-MC-Unique: MlaYF3UGOx6deQkXqWLQWg-1 From: Laine Stump To: devel@lists.libvirt.org Subject: [PATCH v5 12/30] network: support setting firewallBackend from network.conf Date: Fri, 17 May 2024 13:29:49 -0400 Message-ID: <20240517173007.8125-13-laine@redhat.com> In-Reply-To: <20240517173007.8125-1-laine@redhat.com> References: <20240517173007.8125-1-laine@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.4.1 on 10.11.54.2 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Content-Transfer-Encoding: quoted-printable Message-ID-Hash: 5GR3JNGQFLGO3SACIWBS63P2YFGCXGW4 X-Message-ID-Hash: 5GR3JNGQFLGO3SACIWBS63P2YFGCXGW4 X-MailFrom: laine@redhat.com X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; emergency; loop; banned-address; member-moderation; header-match-config-1; header-match-config-2; header-match-config-3; header-match-devel.lists.libvirt.org-0; nonmember-moderation; administrivia; implicit-dest; max-recipients; max-size; news-moderation; no-subject; suspicious-header X-Mailman-Version: 3.2.2 Precedence: list List-Id: Development discussions about the libvirt library & tools Archived-At: List-Archive: List-Help: List-Post: List-Subscribe: List-Unsubscribe: X-ZohoMail-DKIM: fail (Header signature does not verify) X-ZM-MESSAGEID: 1715968212778100001 Content-Type: text/plain; charset="utf-8"; x-default="true" It still can have only one useful value ("iptables"), but once a 2nd value is supported, it will be selectable by setting "firewall_backend=3Dnftables" in /etc/libvirt/network.conf. If firewall_backend isn't set in network.conf, then libvirt will check to see if FIREWALL_BACKEND_DEFAULT_1 is available and, if so, set that. (Since FIREWALL_BACKEND_DEFAULT_1 is currently "iptables", this means checking to see it the iptables binary is present on the system). If the default backend isn't available, that is considered a fatal error (since no networks can be started anyway), so an error is logged and startup of the network driver fails. NB: network.conf is itself created from network.conf.in at build time, and the advertised default setting of firewall_backend (in a commented out line) is set from the meson_options.txt setting "firewall_backend_default_1". This way the conf file will have correct information no matter what ordering is chosen for default backend at build time (as more backends are added, settings will be added for "firewall_backend_default_n", and those will be settable in meson_options.txt and on the meson commandline to change the ordering of the auto-detection when no backend is set in network.conf). virNetworkLoadDriverConfig() may look more complicated than necessary, but as additional backends are added, it will be easier to add checks for those backends (and to re-order the checks based on builders' preferences). Signed-off-by: Laine Stump --- meson.build | 4 ++ meson_options.txt | 1 + src/network/bridge_driver.c | 22 +++---- src/network/bridge_driver_conf.c | 75 +++++++++++++++++++++--- src/network/bridge_driver_conf.h | 3 + src/network/bridge_driver_linux.c | 6 +- src/network/bridge_driver_nop.c | 6 +- src/network/bridge_driver_platform.h | 6 +- src/network/libvirtd_network.aug | 5 +- src/network/meson.build | 22 ++++++- src/network/network.conf.in | 8 +++ src/network/test_libvirtd_network.aug.in | 3 + tests/networkxml2firewalltest.c | 2 +- 13 files changed, 134 insertions(+), 29 deletions(-) diff --git a/meson.build b/meson.build index 063233e05e..af3719a734 100644 --- a/meson.build +++ b/meson.build @@ -1638,6 +1638,10 @@ endif =20 if not get_option('driver_network').disabled() and conf.has('WITH_LIBVIRTD= ') conf.set('WITH_NETWORK', 1) + firewall_backend_default_1 =3D get_option('firewall_backend_default_1') + firewall_backend_default_conf =3D firewall_backend_default_1 + firewall_backend_default_1 =3D 'VIR_FIREWALL_BACKEND_' + firewall_backen= d_default_1.to_upper() + conf.set('FIREWALL_BACKEND_DEFAULT_1', firewall_backend_default_1) elif get_option('driver_network').enabled() error('libvirtd must be enabled to build the network driver') endif diff --git a/meson_options.txt b/meson_options.txt index 6258e50c91..41342793bc 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -115,6 +115,7 @@ option('dtrace', type: 'feature', value: 'auto', descri= ption: 'use dtrace for st option('firewalld', type: 'feature', value: 'auto', description: 'firewall= d support') # dep:firewalld option('firewalld_zone', type: 'feature', value: 'auto', description: 'whe= ther to install firewalld libvirt zone') +option('firewall_backend_default_1', type: 'string', value: 'iptables', de= scription: 'first firewall backend to try when none is specified') option('host_validate', type: 'feature', value: 'auto', description: 'buil= d virt-host-validate') option('init_script', type: 'combo', choices: ['systemd', 'openrc', 'check= ', 'none'], value: 'check', description: 'Style of init script to install') option('loader_nvram', type: 'string', value: '', description: 'Pass list = of pairs of : paths. Both pairs and list items are separated= by a colon.') diff --git a/src/network/bridge_driver.c b/src/network/bridge_driver.c index e5f9ecf9e8..82e1052978 100644 --- a/src/network/bridge_driver.c +++ b/src/network/bridge_driver.c @@ -1682,6 +1682,7 @@ static int networkReloadFirewallRulesHelper(virNetworkObj *obj, void *opaque G_GNUC_UNUSED) { + g_autoptr(virNetworkDriverConfig) cfg =3D virNetworkDriverGetConfig(ne= tworkGetDriver()); VIR_LOCK_GUARD lock =3D virObjectLockGuard(obj); virNetworkDef *def =3D virNetworkObjGetDef(obj); =20 @@ -1695,8 +1696,8 @@ networkReloadFirewallRulesHelper(virNetworkObj *obj, * network type, forward=3D'open', doesn't need this because it * has no iptables rules. */ - networkRemoveFirewallRules(def); - ignore_value(networkAddFirewallRules(def)); + networkRemoveFirewallRules(def, cfg->firewallBackend); + ignore_value(networkAddFirewallRules(def, cfg->firewallBackend= )); break; =20 case VIR_NETWORK_FORWARD_OPEN: @@ -1948,7 +1949,7 @@ networkStartNetworkVirtual(virNetworkDriverState *dri= ver, =20 /* Add "once per network" rules */ if (def->forward.type !=3D VIR_NETWORK_FORWARD_OPEN && - networkAddFirewallRules(def) < 0) + networkAddFirewallRules(def, cfg->firewallBackend) < 0) goto error; =20 firewalRulesAdded =3D true; @@ -2066,7 +2067,7 @@ networkStartNetworkVirtual(virNetworkDriverState *dri= ver, =20 if (firewalRulesAdded && def->forward.type !=3D VIR_NETWORK_FORWARD_OPEN) - networkRemoveFirewallRules(def); + networkRemoveFirewallRules(def, cfg->firewallBackend); =20 virNetworkObjUnrefMacMap(obj); =20 @@ -2078,7 +2079,8 @@ networkStartNetworkVirtual(virNetworkDriverState *dri= ver, =20 =20 static int -networkShutdownNetworkVirtual(virNetworkObj *obj) +networkShutdownNetworkVirtual(virNetworkObj *obj, + virNetworkDriverConfig *cfg) { virNetworkDef *def =3D virNetworkObjGetDef(obj); pid_t dnsmasqPid; @@ -2104,7 +2106,7 @@ networkShutdownNetworkVirtual(virNetworkObj *obj) ignore_value(virNetDevSetOnline(def->bridge, false)); =20 if (def->forward.type !=3D VIR_NETWORK_FORWARD_OPEN) - networkRemoveFirewallRules(def); + networkRemoveFirewallRules(def, cfg->firewallBackend); =20 ignore_value(virNetDevBridgeDelete(def->bridge)); =20 @@ -2408,7 +2410,7 @@ networkShutdownNetwork(virNetworkDriverState *driver, case VIR_NETWORK_FORWARD_NAT: case VIR_NETWORK_FORWARD_ROUTE: case VIR_NETWORK_FORWARD_OPEN: - ret =3D networkShutdownNetworkVirtual(obj); + ret =3D networkShutdownNetworkVirtual(obj, cfg); break; =20 case VIR_NETWORK_FORWARD_BRIDGE: @@ -3259,7 +3261,7 @@ networkUpdate(virNetworkPtr net, * old rules (and remember to load new ones after the * update). */ - networkRemoveFirewallRules(def); + networkRemoveFirewallRules(def, cfg->firewallBackend); needFirewallRefresh =3D true; break; default: @@ -3287,14 +3289,14 @@ networkUpdate(virNetworkPtr net, parentIndex, xml, network_driver->xmlopt, flags) < 0) { if (needFirewallRefresh) - ignore_value(networkAddFirewallRules(def)); + ignore_value(networkAddFirewallRules(def, cfg->firewallBackend= )); goto cleanup; } =20 /* @def is replaced */ def =3D virNetworkObjGetDef(obj); =20 - if (needFirewallRefresh && networkAddFirewallRules(def) < 0) + if (needFirewallRefresh && networkAddFirewallRules(def, cfg->firewallB= ackend) < 0) goto cleanup; =20 if (flags & VIR_NETWORK_UPDATE_AFFECT_CONFIG) { diff --git a/src/network/bridge_driver_conf.c b/src/network/bridge_driver_c= onf.c index a2edafa837..06abab516a 100644 --- a/src/network/bridge_driver_conf.c +++ b/src/network/bridge_driver_conf.c @@ -25,6 +25,7 @@ #include "datatypes.h" #include "virlog.h" #include "virerror.h" +#include "virfile.h" #include "virutil.h" #include "bridge_driver_conf.h" =20 @@ -32,7 +33,6 @@ =20 VIR_LOG_INIT("network.bridge_driver"); =20 - static virClass *virNetworkDriverConfigClass; static void virNetworkDriverConfigDispose(void *obj); =20 @@ -62,18 +62,75 @@ virNetworkLoadDriverConfig(virNetworkDriverConfig *cfg = G_GNUC_UNUSED, const char *filename) { g_autoptr(virConf) conf =3D NULL; + g_autofree char *fwBackendStr =3D NULL; + bool fwBackendSelected =3D false; + size_t i; + int fwBackends[] =3D { FIREWALL_BACKEND_DEFAULT_1 }; + G_STATIC_ASSERT(G_N_ELEMENTS(fwBackends) =3D=3D VIR_FIREWALL_BACKEND_L= AST); + + if (access(filename, R_OK) =3D=3D 0) { + + conf =3D virConfReadFile(filename, 0); + if (!conf) + return -1; + + /* use virConfGetValue*(conf, ...) functions to read any settings = into cfg */ + + if (virConfGetValueString(conf, "firewall_backend", &fwBackendStr)= < 0) + return -1; + + if (fwBackendStr) { + fwBackends[0] =3D virFirewallBackendTypeFromString(fwBackendSt= r); + + if (fwBackends[0] < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("unrecognized 'firewall_backend =3D '%1$s= ' set in network driver config file %2$s"), + fwBackendStr, filename); + return -1; + } + VIR_INFO("firewall_backend setting requested from config file = %s: '%s'", + virFirewallBackendTypeToString(fwBackends[0]), filena= me); + } + } =20 - /* if file doesn't exist or is unreadable, ignore the "error" */ - if (access(filename, R_OK) =3D=3D -1) - return 0; + for (i =3D 0; i < G_N_ELEMENTS(fwBackends) && !fwBackendSelected; i++)= { =20 - conf =3D virConfReadFile(filename, 0); - if (!conf) - return -1; + switch ((virFirewallBackend)fwBackends[i]) { + case VIR_FIREWALL_BACKEND_IPTABLES: { + g_autofree char *iptablesInPath =3D virFindFileInPath(IPTABLES= ); =20 - /* use virConfGetValue*(conf, ...) functions to read any settings into= cfg */ + if (iptablesInPath) + fwBackendSelected =3D true; + break; + } + case VIR_FIREWALL_BACKEND_LAST: + virReportEnumRangeError(virFirewallBackend, fwBackends[i]); + return -1; + } =20 - return 0; + if (fwBackendSelected) { + + cfg->firewallBackend =3D fwBackends[i]; + + } else if (fwBackendStr) { + + /* explicitly requested backend not found - this is a failure = */ + virReportError(VIR_ERR_INTERNAL_ERROR, + _("requested firewall_backend '%1$s' is not ava= ilable"), + virFirewallBackendTypeToString(fwBackends[i])); + return -1; + } + } + + if (fwBackendSelected) { + VIR_INFO("using firewall_backend: '%s'", + virFirewallBackendTypeToString(cfg->firewallBackend)); + return 0; + } else { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("could not find a usable firewall backend")); + return -1; + } } =20 =20 diff --git a/src/network/bridge_driver_conf.h b/src/network/bridge_driver_c= onf.h index 426c16198d..8f221f391e 100644 --- a/src/network/bridge_driver_conf.h +++ b/src/network/bridge_driver_conf.h @@ -26,6 +26,7 @@ #include "virdnsmasq.h" #include "virnetworkobj.h" #include "object_event.h" +#include "virfirewall.h" =20 typedef struct _virNetworkDriverConfig virNetworkDriverConfig; struct _virNetworkDriverConfig { @@ -37,6 +38,8 @@ struct _virNetworkDriverConfig { char *stateDir; char *pidDir; char *dnsmasqStateDir; + + virFirewallBackend firewallBackend; }; =20 G_DEFINE_AUTOPTR_CLEANUP_FUNC(virNetworkDriverConfig, virObjectUnref); diff --git a/src/network/bridge_driver_linux.c b/src/network/bridge_driver_= linux.c index 4914d5c903..c2ef27f251 100644 --- a/src/network/bridge_driver_linux.c +++ b/src/network/bridge_driver_linux.c @@ -303,7 +303,8 @@ int networkCheckRouteCollision(virNetworkDef *def) =20 =20 int -networkAddFirewallRules(virNetworkDef *def) +networkAddFirewallRules(virNetworkDef *def, + virFirewallBackend firewallBackend G_GNUC_UNUSED) { if (virOnce(&createdOnce, networkSetupPrivateChains) < 0) return -1; @@ -394,7 +395,8 @@ networkAddFirewallRules(virNetworkDef *def) =20 =20 void -networkRemoveFirewallRules(virNetworkDef *def) +networkRemoveFirewallRules(virNetworkDef *def, + virFirewallBackend firewallBackend G_GNUC_UNUSE= D) { iptablesRemoveFirewallRules(def); } diff --git a/src/network/bridge_driver_nop.c b/src/network/bridge_driver_no= p.c index 6eee6043e6..7d9a061e50 100644 --- a/src/network/bridge_driver_nop.c +++ b/src/network/bridge_driver_nop.c @@ -36,11 +36,13 @@ int networkCheckRouteCollision(virNetworkDef *def G_GNU= C_UNUSED) return 0; } =20 -int networkAddFirewallRules(virNetworkDef *def G_GNUC_UNUSED) +int networkAddFirewallRules(virNetworkDef *def G_GNUC_UNUSED, + virFirewallBackend firewallBackend G_GNUC_UNUS= ED) { return 0; } =20 -void networkRemoveFirewallRules(virNetworkDef *def G_GNUC_UNUSED) +void networkRemoveFirewallRules(virNetworkDef *def G_GNUC_UNUSED, + virFirewallBackend firewallBackend G_GNUC_U= NUSED) { } diff --git a/src/network/bridge_driver_platform.h b/src/network/bridge_driv= er_platform.h index b720d343be..7443c3129f 100644 --- a/src/network/bridge_driver_platform.h +++ b/src/network/bridge_driver_platform.h @@ -32,6 +32,8 @@ void networkPostReloadFirewallRules(bool startup); =20 int networkCheckRouteCollision(virNetworkDef *def); =20 -int networkAddFirewallRules(virNetworkDef *def); +int networkAddFirewallRules(virNetworkDef *def, + virFirewallBackend firewallBackend); =20 -void networkRemoveFirewallRules(virNetworkDef *def); +void networkRemoveFirewallRules(virNetworkDef *def, + virFirewallBackend firewallBackend); diff --git a/src/network/libvirtd_network.aug b/src/network/libvirtd_networ= k.aug index ae153d96a1..5d6d72dd92 100644 --- a/src/network/libvirtd_network.aug +++ b/src/network/libvirtd_network.aug @@ -22,11 +22,14 @@ module Libvirtd_network =3D let int_entry (kw:string) =3D [ key kw . value_sep . int_val ] let str_array_entry (kw:string) =3D [ key kw . value_sep . str_array_va= l ] =20 + let firewall_backend_entry =3D str_entry "firewall_backend" + (* Each entry in the config is one of the following *) + let entry =3D firewall_backend_entry let comment =3D [ label "#comment" . del /#[ \t]*/ "# " . store /([^ \= t\n][^\n]*)?/ . del /\n/ "\n" ] let empty =3D [ label "#empty" . eol ] =20 - let record =3D indent . eol + let record =3D indent . entry . eol =20 let lns =3D ( record | comment | empty ) * =20 diff --git a/src/network/meson.build b/src/network/meson.build index 0336435862..c1934d2e68 100644 --- a/src/network/meson.build +++ b/src/network/meson.build @@ -49,16 +49,34 @@ if conf.has('WITH_NETWORK') ], } =20 + network_options_conf =3D configuration_data({ + 'FIREWALL_BACKEND': firewall_backend_default_conf, + }) + network_conf =3D configure_file( input: 'network.conf.in', output: 'network.conf', - configuration: configmake_conf, + configuration: network_options_conf, ) + + network_options_hack_conf =3D configuration_data({ + 'FIREWALL_BACKEND': firewall_backend_default_conf, + # This hack is necessary because the output file is going to be + # used as input for another configure_file() call later, which + # will take care of substituting @CONFIG@ with useful data + 'CONFIG': '@CONFIG@', + }) + test_libvirtd_network_aug_tmp =3D configure_file( + input: 'test_libvirtd_network.aug.in', + output: 'test_libvirtd_network.aug.tmp', + configuration: network_options_hack_conf, + ) + virt_conf_files +=3D network_conf virt_aug_files +=3D files('libvirtd_network.aug') virt_test_aug_files +=3D { 'name': 'test_libvirtd_network.aug', - 'aug': files('test_libvirtd_network.aug.in'), + 'aug': test_libvirtd_network_aug_tmp, 'conf': network_conf, 'test_name': 'libvirtd_network', 'test_srcdir': meson.current_source_dir(), diff --git a/src/network/network.conf.in b/src/network/network.conf.in index 5c84003f6d..ec75e125d8 100644 --- a/src/network/network.conf.in +++ b/src/network/network.conf.in @@ -1,3 +1,11 @@ # Master configuration file for the network driver. # All settings described here are optional - if omitted, sensible # defaults are used. + +# firewall_backend: +# +# determines which subsystem to use to setup firewall packet +# filtering rules for virtual networks. Currently the only supported +# selection is "iptables". +# +#firewall_backend =3D "@FIREWALL_BACKEND@" diff --git a/src/network/test_libvirtd_network.aug.in b/src/network/test_li= bvirtd_network.aug.in index ffdca520ce..9e29a9192f 100644 --- a/src/network/test_libvirtd_network.aug.in +++ b/src/network/test_libvirtd_network.aug.in @@ -1,2 +1,5 @@ module Test_libvirtd_network =3D @CONFIG@ + + test Libvirtd_network.lns get conf =3D +{ "firewall_backend" =3D "@FIREWALL_BACKEND@" } diff --git a/tests/networkxml2firewalltest.c b/tests/networkxml2firewalltes= t.c index cb66a26294..3a9f409e2a 100644 --- a/tests/networkxml2firewalltest.c +++ b/tests/networkxml2firewalltest.c @@ -98,7 +98,7 @@ static int testCompareXMLToArgvFiles(const char *xml, if (!(def =3D virNetworkDefParse(NULL, xml, NULL, false))) return -1; =20 - if (networkAddFirewallRules(def) < 0) + if (networkAddFirewallRules(def, VIR_FIREWALL_BACKEND_IPTABLES) < 0) return -1; =20 actual =3D actualargv =3D virBufferContentAndReset(&buf); --=20 2.45.0