From 0978fb2e89507fc140bee688ba42e57d3164bf31 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Knut=20Alejandro=20Anderssen=20Gonz=C3=A1lez?= Date: Thu, 9 Nov 2017 07:57:26 +0000 Subject: [PATCH 1/8] Firewalld: Handle of interface zone changes --- src/include/network/lan/address.rb | 25 +--- src/lib/network/firewalld_interface_zones.rb | 126 +++++++++++++++++++ src/modules/Lan.rb | 13 +- src/modules/LanItems.rb | 3 + 4 files changed, 142 insertions(+), 25 deletions(-) create mode 100644 src/lib/network/firewalld_interface_zones.rb diff --git a/src/include/network/lan/address.rb b/src/include/network/lan/address.rb index e14260b48..ed01005a2 100644 --- a/src/include/network/lan/address.rb +++ b/src/include/network/lan/address.rb @@ -27,6 +27,7 @@ # Authors: Michal Svec # require "ui/text_helpers" +require "y2firewall/firewalld" module Yast module NetworkLanAddressInclude @@ -70,8 +71,6 @@ def initialize_network_lan_address(include_target) @settings = {} - @fwzone_initial = "" - @force_static_ip = ProductFeatures.GetBooleanFeature( "network", "force_static_ip" @@ -1287,18 +1286,6 @@ def wireless_tab # Dialog for setting up IP address # @return dialog result def AddressDialog - fwzone = SuSEFirewall4Network.GetZoneOfInterface(LanItems.GetCurrentName) - - # If firewall is active and interface in no zone, nothing - # gets through (#62309) so add it to the default zone - if fwzone == "" && LanItems.operation == :add && SuSEFirewall4Network.IsOn && - SuSEFirewall4Network.UnconfiguredIsBlocked - fwzone = "public" - Builtins.y2milestone("Defaulting to public") - end - - @fwzone_initial = fwzone - initialize_address_settings wd = Convert.convert( @@ -1428,13 +1415,7 @@ def AddressDialog ifcfgname = Ops.get_string(LanItems.getCurrentItem, "ifcfg", "") # general tab LanItems.startmode = Ops.get_string(@settings, "STARTMODE", "") - - if SuSEFirewall4Network.IsInstalled - zone = Ops.get_string(@settings, "FWZONE", "") - SuSEFirewall4Network.ChangedByUser(true) if zone != @fwzone_initial - SuSEFirewall4Network.ProtectByFirewall(ifcfgname, zone, zone != "") - end - + LanItems.firewall_zone = @settings.fetch("FWZONE", "") LanItems.mtu = Ops.get_string(@settings, "MTU", "") # address tab @@ -1509,7 +1490,7 @@ def initialize_address_settings "STARTMODE" => LanItems.startmode, "IFPLUGD_PRIORITY" => LanItems.ifplugd_priority, # problems when renaming the interface? - "FWZONE" => @fwzone_initial, + "FWZONE" => LanItems.firewall_zone, "MTU" => LanItems.mtu, # address tab: "BOOTPROTO" => LanItems.bootproto, diff --git a/src/lib/network/firewalld_interface_zones.rb b/src/lib/network/firewalld_interface_zones.rb new file mode 100644 index 000000000..b76ccc029 --- /dev/null +++ b/src/lib/network/firewalld_interface_zones.rb @@ -0,0 +1,126 @@ +# encoding: utf-8 +# +# *************************************************************************** +# +# Copyright (c) 2017 SUSE LLC. +# All Rights Reserved. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of version 2 or 3 of the GNU General +# Public License as published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, contact SUSE LLC. +# +# To contact SUSE about this file by physical or electronic mail, +# you may find current contact information at www.suse.com +# +# *************************************************************************** + +require "yast" +require "singleton" +require "y2firewall/firewalld" + +Yast.import "NetworkInterfaces" + +module Yast + # This class is responsible of update the state of network interfaces zones + # in firewalld. + class FirewalldInterfaceZones + include Singleton + include Logger + include I18n + # Maintains the original interface zones map. + attr_accessor :original + + # Constructor + def initialize + read + end + + # Sets the current configuration as the original. + def read + @original = current + end + + # Perform in firewalld the changes between the original and current state. + def apply_changes + removed_interfaces.each { |i| remove_interface(i) } + added_interfaces.each { |i| change_interface(i) } + modified_interfaces.each { |i| change_interface(i) } + end + + # Obtain current interfaces zones. + # + # return [Hash] + def current + interface_zone = {} + + NetworkInterfaces.List("").map do |name| + interface_zone[name] = + { + id: name, + description: get_value(name, "NAME"), + zone: get_value(name, "ZONE") + } + end + + interface_zone + end + + private + + # @return [Y2Firewalld::Firewalld] singleton instance + def firewalld + Y2Firewall::Firewalld.instance + end + + # Convenience method for obtain the value of a specific network interface + # attribute. + # + # @param name [String] network interface name + # @param value [String] network interface attribute + # @return [String] the value of the given attribute + def get_value(name, attribute) + NetworkInterfaces::GetValue(name, attribute) + end + + # @return [Array] removed interface names + def removed_interfaces + original.keys - current.keys + end + + # @return [Array] added interface names + def added_interfaces + current.keys - original.keys + end + + # @return [Array] modified interface names + def modified_interfaces + current.select { |k, v| original[k] && (original[k][:zone] != v[:zone]) }.keys + end + + # Convenience method for remove an interface from a firewalld zone + def remove_interface(name) + log.info("Removing interface #{name} from its original zone #{original[name][:zone]}.") + + firewalld.api.remove_interface(original[name], original[name][:zone]) + end + + # Convenience method for change an interface to its current firewalld zone + def change_interface(name) + zone = current.fetch(name, {}).fetch(:zone, "") + if zone.empty? + remove_interface(name) if original[name] + else + log.info("Changing interface #{name} to zone #{zone}") + firewalld.api.change_interface(zone, name) + end + end + end +end diff --git a/src/modules/Lan.rb b/src/modules/Lan.rb index 90962066c..22ea96156 100644 --- a/src/modules/Lan.rb +++ b/src/modules/Lan.rb @@ -31,6 +31,8 @@ # Input and output routines. require "yast" require "network/confirm_virt_proposal" +require "network/firewalld_interface_zones" +require "y2firewall/firewalld" module Yast class LanClass < Module @@ -362,7 +364,7 @@ def Read(cache) # Progress step 5/9 ProgressNextStage(_("Reading firewall settings...")) if @gui orig = Progress.set(false) - SuSEFirewall4Network.Read + FirewalldInterfaceZones.instance.read Progress.set(orig) if @gui Builtins.sleep(sl) @@ -485,7 +487,7 @@ def Write(gui: true) return true end - fw_is_installed = SuSEFirewall4Network.IsInstalled + fw_is_installed = firewalld.installed? # Write dialog caption caption = _("Saving Network Configuration") @@ -511,6 +513,7 @@ def Write(gui: true) if fw_is_installed step_labels = Builtins.add(step_labels, _("Write firewall settings")) end + # Progress stage 9 if !@write_only step_labels = Builtins.add(step_labels, _("Activate network services")) @@ -577,7 +580,7 @@ def Write(gui: true) # Progress step 8 ProgressNextStage(_("Writing firewall settings...")) orig = Progress.set(false) - SuSEFirewall4Network.Write + FirewalldInterfaceZones.instance.apply_changes Progress.set(orig) Builtins.sleep(sl) end @@ -1099,6 +1102,10 @@ def HaveXenBridge private + def firewalld + Y2Firewall::Firewalld.instance + end + def activate_network_service # If the second installation stage has been called by yast.ssh via # ssh, we should not restart network because systemctl diff --git a/src/modules/LanItems.rb b/src/modules/LanItems.rb index eb62df936..3bba590ac 100644 --- a/src/modules/LanItems.rb +++ b/src/modules/LanItems.rb @@ -47,6 +47,7 @@ module Yast class LanItemsClass < Module attr_reader :ipoib_modes attr_accessor :ipoib_mode + attr_accessor :firewall_zone include Logger include Wicked @@ -1679,6 +1680,7 @@ def SetDeviceVars(devmap, defaults) @prefix = d["PREFIXLEN"] @remoteip = d["REMOTE_IPADDR"] @netmask = d["NETMASK"] + @firewall_zone = d["ZONE"] @set_default_route = case d["DHCLIENT_SET_DEFAULT_ROUTE"] when "yes" then true when "no" then false @@ -1975,6 +1977,7 @@ def Commit end end + newdev["ZONE"] = @firewall_zone newdev["NAME"] = @description newdev = setup_basic_device_options(newdev) From 9b823d4645ce95d956a29ca02e229207a2917d78 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Knut=20Alejandro=20Anderssen=20Gonz=C3=A1lez?= Date: Thu, 23 Nov 2017 18:14:06 +0000 Subject: [PATCH 2/8] Removed not needed client. --- doc/features.md | 1 - src/clients/firewall_stage1_finish.rb | 86 ----- src/clients/firewall_stage1_proposal.rb | 446 ------------------------ test/Makefile.am | 1 - test/firewall_stage1_proposal_test.rb | 61 ---- 5 files changed, 595 deletions(-) delete mode 100644 src/clients/firewall_stage1_finish.rb delete mode 100644 src/clients/firewall_stage1_proposal.rb delete mode 100755 test/firewall_stage1_proposal_test.rb diff --git a/doc/features.md b/doc/features.md index 79787645e..9d31c2ae3 100644 --- a/doc/features.md +++ b/doc/features.md @@ -65,7 +65,6 @@ s390 Devices Firewall Parts -------------- -- stage1 proposal + write it down ( firewall enable/disable, sshd enable/disable, ssh port open/close, vnc enable/disable) - assign network device to firewall zone Network Storage Devices diff --git a/src/clients/firewall_stage1_finish.rb b/src/clients/firewall_stage1_finish.rb deleted file mode 100644 index 326f997bb..000000000 --- a/src/clients/firewall_stage1_finish.rb +++ /dev/null @@ -1,86 +0,0 @@ -# encoding: utf-8 - -# *************************************************************************** -# -# Copyright (c) 2012 Novell, Inc. -# All Rights Reserved. -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of version 2 of the GNU General Public License as -# published by the Free Software Foundation. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, contact Novell, Inc. -# -# To contact Novell about this file by physical or electronic mail, -# you may find current contact information at www.novell.com -# -# ************************************************************************** -# File: clients/firewall_stage1_finish.ycp -# Summary: Installation client for writing firewall configuration -# at the end of 1st stage -# Author: Bubli -# -require "yast" - -module Yast - class FirewallStage1FinishClient < Client - def main - textdomain "network" - - Yast.import "Service" - Yast.import "SuSEFirewall" - Yast.import "SuSEFirewall4Network" - - @ret = nil - @func = "" - @param = {} - - # Check arguments - if Ops.greater_than(Builtins.size(WFM.Args), 0) && - Ops.is_string?(WFM.Args(0)) - @func = Convert.to_string(WFM.Args(0)) - if Ops.greater_than(Builtins.size(WFM.Args), 1) && - Ops.is_map?(WFM.Args(1)) - @param = Convert.to_map(WFM.Args(1)) - end - end - - Builtins.y2milestone("starting firewall_stage1_finish") - Builtins.y2debug("func=%1", @func) - Builtins.y2debug("param=%1", @param) - - case @func - when "Info" - return { - "steps" => 1, - # progress step title - "title" => _( - "Writing Firewall Configuration..." - ), - "when" => [:installation, :autoinst] - } - when "Write" - # Enable SSH service independent of port open (bnc#865056) - Service.Enable("sshd") if SuSEFirewall4Network.EnabledSshd - - # This is equivalent to write-only, do not attempt to restart the service - SuSEFirewall.WriteConfiguration - else - Builtins.y2error("unknown function: %1", @func) - @ret = nil - end - - Builtins.y2debug("ret=%1", @ret) - Builtins.y2milestone("firewall_stage1_finish finished") - deep_copy(@ret) - end - end -end - -Yast::FirewallStage1FinishClient.new.main diff --git a/src/clients/firewall_stage1_proposal.rb b/src/clients/firewall_stage1_proposal.rb deleted file mode 100644 index 9373fb510..000000000 --- a/src/clients/firewall_stage1_proposal.rb +++ /dev/null @@ -1,446 +0,0 @@ -# encoding: utf-8 - -# *************************************************************************** -# -# Copyright (c) 2008 - 2012 Novell, Inc. -# All Rights Reserved. -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of version 2 of the GNU General Public License as -# published by the Free Software Foundation. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, contact Novell, Inc. -# -# To contact Novell about this file by physical or electronic mail, -# you may find current contact information at www.novell.com -# -# ************************************************************************** - -# File: firewall_stage1_proposal.ycp -# Author: Bubli -# -require "yast" - -# yast namespace -module Yast - # Configuration of fw in 1st stage - class FirewallStage1ProposalClient < Client - PROPOSAL_ID = "fw_1ststage".freeze - - LINK_ENABLE_FIREWALL = "firewall--enable_firewall_in_proposal".freeze - LINK_DISABLE_FIREWALL = "firewall--disable_firewall_in_proposal".freeze - LINK_OPEN_SSH_PORT = "firewall--enable_ssh_port_in_proposal".freeze - LINK_BLOCK_SSH_PORT = "firewall--disable_ssh_port_in_proposal".freeze - LINK_ENABLE_SSHD = "firewall--enable_sshd_in_proposal".freeze - LINK_DISABLE_SSHD = "firewall--disable_sshd_in_proposal".freeze - LINK_ENABLE_VNC = "firewall--enable_vnc_in_proposal".freeze - LINK_DISABLE_VNC = "firewall--disable_vnc_in_proposal".freeze - LINK_FIREWALL_DIALOG = "firewall_stage1".freeze - - # Namespace for UI constants - module ID - SSH_PORT = "open_ssh_port".freeze - VNC_PORT = "open_vnc_port".freeze - ENABLE_FW = "enable_fw".freeze - ENABLE_SSHD = "enable_sshd".freeze - end - - include Yast::Logger - - def main - Yast.import "UI" - textdomain "network" - - Yast.import "Label" - Yast.import "Linuxrc" - Yast.import "PackagesProposal" - Yast.import "ProductControl" - Yast.import "Progress" - Yast.import "SuSEFirewall" - Yast.import "SuSEFirewall4Network" - Yast.import "SuSEFirewallProposal" - Yast.import "Wizard" - - script_command = WFM.Args(0) - params = WFM.Args(1) || {} - script_return = {} - - case script_command - when "MakeProposal" - # Don't override users settings - SuSEFirewall4Network.prepare_proposal unless SuSEFirewallProposal.GetChangedByUser - - # this method is not easily mockable in rspec and currently is out of scope - # for testing in firewall_stage1_proposal_test.rb - adjust_configuration if !Mode.test - - script_return = { - "preformatted_proposal" => preformatted_proposal, - "warning_level" => :warning, - "links" => [ - LINK_ENABLE_FIREWALL, - LINK_DISABLE_FIREWALL, - LINK_OPEN_SSH_PORT, - LINK_BLOCK_SSH_PORT, - LINK_ENABLE_SSHD, - LINK_DISABLE_SSHD, - LINK_ENABLE_VNC, - LINK_DISABLE_VNC - ] - } - when "AskUser" - chosen_link = params["chosen_id"] - result = :next - log.info "User clicked #{chosen_link}" - - case chosen_link - when LINK_ENABLE_FIREWALL - log.info "Enabling FW" - SuSEFirewall4Network.SetEnabled1stStage(true) - when LINK_DISABLE_FIREWALL - log.info "Disabling FW" - SuSEFirewall4Network.SetEnabled1stStage(false) - when LINK_OPEN_SSH_PORT - log.info "Opening SSH port" - SuSEFirewall4Network.SetSshEnabled1stStage(true) - when LINK_BLOCK_SSH_PORT - log.info "Blocking SSH port" - SuSEFirewall4Network.SetSshEnabled1stStage(false) - when LINK_ENABLE_SSHD - log.info "Enabling SSHD" - SuSEFirewall4Network.SetSshdEnabled(true) - when LINK_DISABLE_SSHD - log.info "Disabling SSHD" - SuSEFirewall4Network.SetSshdEnabled(false) - when LINK_ENABLE_VNC - log.info "Enabling VNC" - SuSEFirewall4Network.SetVncEnabled1stStage(true) - when LINK_DISABLE_VNC - log.info "Disabling VNC" - SuSEFirewall4Network.SetVncEnabled1stStage(false) - when LINK_FIREWALL_DIALOG - result = FirewallDialogSimple() - else - raise "INTERNAL ERROR: unknown action '#{@chosen_link}' for proposal client" - end - - SuSEFirewallProposal.SetChangedByUser(true) - - adjust_configuration - - script_return = { "workflow_sequence" => result } - when "Description" - script_return = { - # Proposal title - "rich_text_title" => _("Firewall and SSH"), - # Menu entry label - "menu_title" => _("&Firewall and SSH"), - "id" => LINK_FIREWALL_DIALOG - } - when "Write" - script_return = { "success" => true } - else - log.error "Unknown command #{script_command}" - end - - deep_copy(script_return) - end - - def FirewallDialogSimple - title = _("Basic Firewall and SSH Configuration") - - contents = VBox( - Frame( - # frame label - _("Firewall and SSH service"), - HSquash( - MarginBox( - 0.5, - 0.5, - VBox( - Left( - CheckBox( - Id(ID::ENABLE_FW), - Opt(:notify), - # TRANSLATORS: check-box label - _("Enable Firewall"), - SuSEFirewall4Network.Enabled1stStage - ) - ), - - Left( - CheckBox( - Id(ID::ENABLE_SSHD), - # TRANSLATORS: check-box label - _("Enable SSH Service"), - SuSEFirewall4Network.EnabledSshd - ) - ), - - sshd_port_ui, - - vnc_ports_ui - ) - ) - ) - ) - ) - - help = _( - "

Firewall and SSH
\n" \ - "Firewall is a defensive mechanism that protects your computer from network attacks.\n" \ - "SSH is a service that allows logging into this computer remotely via dedicated\n" \ - "SSH client

" - ) + - _( - "

Here you can choose whether the firewall will be enabled or disabled after\nthe installation. It is recommended to keep it enabled.

" - ) + - _( - "

With enabled firewall, you can decide whether to open firewall port for SSH\n" \ - "service and allow remote SSH logins. Independently you can also enable SSH service (i.e. it\n" \ - "will be started on computer boot).

" - ) + ( - if Linuxrc.vnc - # TRANSLATORS: help text - _( - "

You can also open VNC ports in firewall. It will not enable\n" \ - "the remote administration service on a running system but it is\n" \ - "started by the installer automatically if needed.

" - ) - else - "" - end - ) - - Wizard.CreateDialog - Wizard.SetTitleIcon("yast-firewall") - - Wizard.SetContentsButtons( - title, - contents, - help, - Label.BackButton, - Label.OKButton - ) - Wizard.SetAbortButton(:cancel, Label.CancelButton) - Wizard.HideBackButton - - UI.ChangeWidget( - Id(ID::SSH_PORT), - :Enabled, - SuSEFirewall4Network.Enabled1stStage - ) - UI.ChangeWidget( - Id(ID::VNC_PORT), - :Enabled, - SuSEFirewall4Network.Enabled1stStage - ) - - dialog_ret = nil - - loop do - dialog_ret = UI.UserInput - enable_firewall = UI.QueryWidget(Id(ID::ENABLE_FW), :Value) - - if dialog_ret == ID::ENABLE_FW - UI.ChangeWidget(Id(ID::SSH_PORT), :Enabled, enable_firewall) - UI.ChangeWidget(Id(ID::VNC_PORT), :Enabled, enable_firewall) - next - elsif dialog_ret == :next || dialog_ret == :ok - open_ssh_port = UI.QueryWidget(Id(ID::SSH_PORT), :Value) - open_vnc_port = UI.QueryWidget(Id(ID::VNC_PORT), :Value) - - SuSEFirewall4Network.SetEnabled1stStage(enable_firewall) - - if enable_firewall - SuSEFirewall4Network.SetSshEnabled1stStage(open_ssh_port) - SuSEFirewall4Network.SetVncEnabled1stStage(open_vnc_port) - end - - SuSEFirewall4Network.SetSshdEnabled( - UI::QueryWidget(Id(ID::ENABLE_SSHD), :Value) - ) - end - - # anything but enabling the firewall closes this dialog - # (VNC and SSH checkboxes do nothing) - break - end - - Wizard.CloseDialog - Convert.to_symbol(dialog_ret) - end - - private - - def preformatted_proposal - firewall_proposal = if SuSEFirewall4Network.Enabled1stStage - _( - "Firewall will be enabled (disable)" - ) % LINK_DISABLE_FIREWALL - else - _( - "Firewall will be disabled (enable)" - ) % LINK_ENABLE_FIREWALL - end - - sshd_proposal = if SuSEFirewall4Network.EnabledSshd - _( - "SSH service will be enabled (disable)" - ) % LINK_DISABLE_SSHD - else - _( - "SSH service will be disabled (enable)" - ) % LINK_ENABLE_SSHD - end - - # Filter proposals with content and sort them - proposals = [firewall_proposal, ssh_fw_proposal, sshd_proposal, vnc_fw_proposal].compact - "
    \n" + proposals.map { |prop| "
  • #{prop}
  • \n" }.join + "
\n" - end - - def sshd_port_ui - return Empty() unless known_firewall_services?(SuSEFirewall4NetworkClass::SSH_SERVICES) - - Left( - CheckBox( - Id(ID::SSH_PORT), - # TRANSLATORS: check-box label - _("Open SSH Port"), - SuSEFirewall4Network.EnabledSsh1stStage - ) - ) - end - - def vnc_ports_ui - return Empty() unless Linuxrc.vnc - return Empty() unless known_firewall_services?(SuSEFirewall4NetworkClass::VNC_SERVICES) - - Left( - CheckBox( - Id(ID::VNC_PORT), - # TRANSLATORS: check-box label - _("Open &VNC Ports"), - SuSEFirewall4Network.EnabledVnc1stStage - ) - ) - end - - # Returns the VNC-port part of the firewall proposal description - # Returns nil if this part should be skipped - # @return [String] proposal html text - def vnc_fw_proposal - # It only makes sense to show the blocked ports if firewall is - # enabled (bnc#886554) - return nil unless SuSEFirewall4Network.Enabled1stStage - return nil unless known_firewall_services?(SuSEFirewall4NetworkClass::VNC_SERVICES) - # Show VNC port only if installing over VNC - return nil unless Linuxrc.vnc - - if SuSEFirewall4Network.EnabledVnc1stStage - _("VNC ports will be open (close)") % LINK_DISABLE_VNC - else - _("VNC ports will be blocked (open)") % LINK_ENABLE_VNC - end - end - - # Returns the SSH-port part of the firewall proposal description - # Returns nil if this part should be skipped - # @return [String] proposal html text - def ssh_fw_proposal - return nil unless SuSEFirewall4Network.Enabled1stStage - return nil unless known_firewall_services?(SuSEFirewall4NetworkClass::SSH_SERVICES) - - if SuSEFirewall4Network.EnabledSsh1stStage - _("SSH port will be open (block)") % LINK_BLOCK_SSH_PORT - else - _("SSH port will be blocked (open)") % LINK_OPEN_SSH_PORT - end - end - - # Returns true if all services are known to firewall - # @param [Array ] services - # @return [Boolean] if all are known - def known_firewall_services?(services) - @all_known_services ||= SuSEFirewallServices.all_services.keys - - (services - @all_known_services).empty? - end - - # Reads and adjust the configuration for SuSEfirewall2 according to the current proposal. - # bnc#887406: This needs to be done before user exports any configuration - # to AutoYast profile. - def adjust_configuration - enable_fw = SuSEFirewall4Network.Enabled1stStage - enable_sshd = SuSEFirewall4Network.EnabledSshd - open_ssh_port = SuSEFirewall4Network.EnabledSsh1stStage - open_vnc_port = SuSEFirewall4Network.EnabledVnc1stStage - - log.info "After installation, firewall will be #{enable_fw ? "enabled" : "disabled"}, " \ - "SSHD will be #{enable_sshd ? "enabled" : "disabled"}, " \ - "SSH port will be #{open_ssh_port ? "open" : "closed"}, " \ - "VNC port will be #{open_vnc_port ? "open" : "closed"}" - - # Read the configuration from sysconfig - # bnc#887406: The file is in inst-sys - previous_state = Progress.set(false) - SuSEFirewall.Read - Progress.set(previous_state) - - SuSEFirewall.SetEnableService(enable_fw) - SuSEFirewall.SetStartService(enable_fw) - - # Request needed packages to be installed - # bnc#893126 - if enable_fw - PackagesProposal.AddResolvables(PROPOSAL_ID, :package, [SuSEFirewall.FIREWALL_PACKAGE]) - else - PackagesProposal.RemoveResolvables(PROPOSAL_ID, :package, [SuSEFirewall.FIREWALL_PACKAGE]) - end - - if enable_sshd - PackagesProposal.AddResolvables(PROPOSAL_ID, :package, [SuSEFirewall4NetworkClass::SSH_PACKAGE]) - else - PackagesProposal.RemoveResolvables(PROPOSAL_ID, :package, [SuSEFirewall4NetworkClass::SSH_PACKAGE]) - end - - # Open or close FW ports depending on user decision - # This can raise an exception if requested service-files are not part of the current system - # For that reason, these files have to be part of the inst-sys - if known_firewall_services?(SuSEFirewall4NetworkClass::SSH_SERVICES) - SuSEFirewall.SetServicesForZones( - SuSEFirewall4NetworkClass::SSH_SERVICES, - SuSEFirewall.GetKnownFirewallZones, - open_ssh_port - ) - else - log.warn "Services #{SuSEFirewall4NetworkClass::SSH_SERVICES} are unknown" - end - - if known_firewall_services?(SuSEFirewall4NetworkClass::VNC_SERVICES) - SuSEFirewall.SetServicesForZones( - SuSEFirewall4NetworkClass::VNC_SERVICES, - SuSEFirewall.GetKnownFirewallZones, - open_vnc_port - ) - else - log.warn "Services #{SuSEFirewall4NetworkClass::VNC_SERVICES} are unknown" - end - - # BNC #766300 - Automatically propose opening iscsi-target port - # when installing with withiscsi=1 - SuSEFirewallProposal.propose_iscsi if Linuxrc.useiscsi - - # Writing the configuration including adjusting services - # is done in firewall_stage1_finish - end - end unless defined? FirewallStage1ProposalClient -end - -Yast::FirewallStage1ProposalClient.new.main diff --git a/test/Makefile.am b/test/Makefile.am index 132c445d7..a2f7f7109 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -8,7 +8,6 @@ TESTS = \ dns_service_test.rb \ dns_test.rb \ edit_nic_name_test.rb \ - firewall_stage1_proposal_test.rb \ hardware_test.rb \ host_test.rb \ ifroute_test.rb \ diff --git a/test/firewall_stage1_proposal_test.rb b/test/firewall_stage1_proposal_test.rb deleted file mode 100755 index 44f8d39bd..000000000 --- a/test/firewall_stage1_proposal_test.rb +++ /dev/null @@ -1,61 +0,0 @@ -#!/usr/bin/env rspec - -require_relative "test_helper" - -require "yast" - -module Yast - extend Yast::I18n - - import "SuSEFirewall4Network" - import "SuSEFirewallProposal" - import "WFM" - - describe "FirewallStage1ProposalClient" do - describe "MakeProposal" do - before(:each) do - # Ensure a fixed proposal - SuSEFirewallProposal.SetChangedByUser(true) - SuSEFirewall4Network.SetSshEnabled1stStage(true) - - allow(SuSEFirewallServices) - .to receive(:all_services) - .and_return(SuSEFirewall4NetworkClass::SSH_SERVICES.zip([]).to_h) - allow(Mode) - .to receive(:test) - .and_return(true) - end - - let(:proposal) do - res = Yast::WFM.CallFunction( - "firewall_stage1_proposal", - ["MakeProposal"] - ) - res["preformatted_proposal"] - end - let(:ssh_string) do - Yast.textdomain "network" - format( - Yast._("SSH port will be open (block)"), - "firewall--disable_ssh_port_in_proposal" - ) - end - - context "when firewall is enabled" do - before { SuSEFirewall4Network.SetEnabled1stStage(true) } - - it "displays ssh port settings" do - expect(proposal).to include ssh_string - end - end - - context "when firewall is disabled" do - before { SuSEFirewall4Network.SetEnabled1stStage(false) } - - it "hides ssh port settings" do - expect(proposal).not_to include ssh_string - end - end - end - end -end From f4866d15da351a7aaa389fef0922128c64f3e57d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Knut=20Alejandro=20Anderssen=20Gonz=C3=A1lez?= Date: Thu, 23 Nov 2017 19:51:57 +0000 Subject: [PATCH 3/8] Use firewalld api to get known_zones. --- src/data/network/sysconfig_defaults.yml | 1 + src/include/network/lan/address.rb | 16 +++++++++++++++- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/src/data/network/sysconfig_defaults.yml b/src/data/network/sysconfig_defaults.yml index e499f6fe8..970a2ca33 100644 --- a/src/data/network/sysconfig_defaults.yml +++ b/src/data/network/sysconfig_defaults.yml @@ -43,3 +43,4 @@ TUNNEL_SET_OWNER: '' TUNNEL_SET_GROUP: '' IPOIB_MODE: connected BRIDGE_PORTS: '' +ZONE: '' diff --git a/src/include/network/lan/address.rb b/src/include/network/lan/address.rb index ed01005a2..5280aa14f 100644 --- a/src/include/network/lan/address.rb +++ b/src/include/network/lan/address.rb @@ -1334,7 +1334,7 @@ def AddressDialog ] ) - wd["FWZONE"]["items"] = firewall_widget + wd["FWZONE"]["items"] = firewall_zones if LanItems.GetCurrentType == "ib" wd["IPOIB_MODE"] = ipoib_mode_widget @@ -1602,5 +1602,19 @@ def initial_hostname(ipaddr) String.FirstChunk(Ops.get(host_list, 0, ""), " \t") end + + def firewall_zones + @firewalld ||= Y2Firewall::Firewalld.instance + zones = [["", _("Automatically Assigned Zone")]] + if @firewalld.installed? + Y2Firewall::Firewalld::Zone.known_zones.map do |name, full_name| + zones << [name, full_name] + end + else + zones = [["", _("Firewall is not installed.")]] + end + + zones + end end end From 09d668c5966148dd305f2e6d5a139b4eea278ec1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Knut=20Alejandro=20Anderssen=20Gonz=C3=A1lez?= Date: Thu, 23 Nov 2017 19:53:09 +0000 Subject: [PATCH 4/8] Rely on wicked to modify interfaces zones --- src/modules/Lan.rb | 67 +++++++++++----------------------------------- 1 file changed, 16 insertions(+), 51 deletions(-) diff --git a/src/modules/Lan.rb b/src/modules/Lan.rb index 22ea96156..4e0972c74 100644 --- a/src/modules/Lan.rb +++ b/src/modules/Lan.rb @@ -31,8 +31,6 @@ # Input and output routines. require "yast" require "network/confirm_virt_proposal" -require "network/firewalld_interface_zones" -require "y2firewall/firewalld" module Yast class LanClass < Module @@ -55,7 +53,6 @@ def main Yast.import "Routing" Yast.import "Progress" Yast.import "String" - Yast.import "SuSEFirewall4Network" Yast.import "FileUtils" Yast.import "PackageSystem" Yast.import "LanItems" @@ -105,7 +102,6 @@ def Modified return true if Routing.Modified return true if NetworkConfig.Modified return true if NetworkService.Modified - return true if SuSEFirewall.GetModified return true if Host.GetModified false @@ -266,23 +262,21 @@ def Read(cache) " ", steps, [ - # Progress stage 1/9 + # Progress stage 1/8 _("Detect network devices"), - # Progress stage 2/9 + # Progress stage 2/8 _("Read driver information"), - # Progress stage 3/9 - multiple devices may be present, really plural + # Progress stage 3/8 - multiple devices may be present, really plural _("Read device configuration"), - # Progress stage 4/9 + # Progress stage 4/8 _("Read network configuration"), - # Progress stage 5/9 - _("Read firewall settings"), - # Progress stage 6/9 + # Progress stage 5/8 _("Read hostname and DNS configuration"), - # Progress stage 7/9 + # Progress stage 6/8 _("Read installation information"), - # Progress stage 8/9 + # Progress stage 8/8 _("Read routing configuration"), - # Progress stage 9/9 + # Progress stage 9/8 _("Detect current status") ], [], @@ -296,7 +290,7 @@ def Read(cache) # if(!Confirm::MustBeRoot()) return false; return false if Abort() - # Progress step 1/9 + # Progress step 1/8 ProgressNextStage(_("Detecting ndiswrapper...")) if @gui # modprobe ndiswrapper before hwinfo when needed (#343893) if !Mode.autoinst && PackageSystem.Installed("ndiswrapper") @@ -337,7 +331,7 @@ def Read(cache) Builtins.sleep(sl) return false if Abort() - # Progress step 2/9 + # Progress step 2/8 ProgressNextStage(_("Detecting network devices...")) if @gui # Dont read hardware data in config mode NetHwDetection.Start if !Mode.config @@ -345,14 +339,14 @@ def Read(cache) Builtins.sleep(sl) return false if Abort() - # Progress step 3/9 - multiple devices may be present, really plural + # Progress step 3/8 - multiple devices may be present, really plural ProgressNextStage(_("Reading device configuration...")) if @gui LanItems.Read Builtins.sleep(sl) return false if Abort() - # Progress step 4/9 + # Progress step 4/8 ProgressNextStage(_("Reading network configuration...")) if @gui NetworkConfig.Read @@ -361,34 +355,26 @@ def Read(cache) Builtins.sleep(sl) return false if Abort() - # Progress step 5/9 - ProgressNextStage(_("Reading firewall settings...")) if @gui - orig = Progress.set(false) - FirewalldInterfaceZones.instance.read - Progress.set(orig) if @gui - Builtins.sleep(sl) - - return false if Abort() - # Progress step 6/9 + # Progress step 5/8 ProgressNextStage(_("Reading hostname and DNS configuration...")) if @gui DNS.Read Host.Read Builtins.sleep(sl) return false if Abort() - # Progress step 7/9 + # Progress step 6/8 ProgressNextStage(_("Reading installation information...")) if @gui # ReadInstallInf(); Builtins.sleep(sl) return false if Abort() - # Progress step 8/9 + # Progress step 7/8 ProgressNextStage(_("Reading routing configuration...")) if @gui Routing.Read Builtins.sleep(sl) return false if Abort() - # Progress step 9/9 + # Progress step 8/8 ProgressNextStage(_("Detecting current status...")) if @gui NetworkService.Read Builtins.sleep(sl) @@ -487,8 +473,6 @@ def Write(gui: true) return true end - fw_is_installed = firewalld.installed? - # Write dialog caption caption = _("Saving Network Configuration") @@ -509,10 +493,6 @@ def Write(gui: true) # Progress stage 7 _("Set up network services") ] - # Progress stage 8 - if fw_is_installed - step_labels = Builtins.add(step_labels, _("Write firewall settings")) - end # Progress stage 9 if !@write_only @@ -574,17 +554,6 @@ def Write(gui: true) writeIPv6 Builtins.sleep(sl) - # Show this only if SuSEfirewall is installed - if fw_is_installed - return false if Abort() - # Progress step 8 - ProgressNextStage(_("Writing firewall settings...")) - orig = Progress.set(false) - FirewalldInterfaceZones.instance.apply_changes - Progress.set(orig) - Builtins.sleep(sl) - end - if !@write_only return false if Abort() # Progress step 9 @@ -1102,10 +1071,6 @@ def HaveXenBridge private - def firewalld - Y2Firewall::Firewalld.instance - end - def activate_network_service # If the second installation stage has been called by yast.ssh via # ssh, we should not restart network because systemctl From 3a09024ded5d2e0ac55d4bdb4c969252757cf4bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Knut=20Alejandro=20Anderssen=20Gonz=C3=A1lez?= Date: Fri, 24 Nov 2017 08:42:02 +0000 Subject: [PATCH 5/8] SuSEFirewall is not touched anymore. --- test/lan_test.rb | 5 ----- 1 file changed, 5 deletions(-) diff --git a/test/lan_test.rb b/test/lan_test.rb index 82e2317a9..8e188e4e3 100755 --- a/test/lan_test.rb +++ b/test/lan_test.rb @@ -174,7 +174,6 @@ def reset_modification_statuses allow(Yast::Routing).to receive(:Modified).and_return false allow(Yast::NetworkConfig).to receive(:Modified).and_return false allow(Yast::NetworkService).to receive(:Modified).and_return false - allow(Yast::SuSEFirewall).to receive(:GetModified).and_return false end def expect_modification_succeedes(modname, method) @@ -208,10 +207,6 @@ def expect_modification_succeedes(modname, method) expect_modification_succeedes(Yast::NetworkService, :Modified) end - it "returns true when SuSEFirewall module was modified" do - expect_modification_succeedes(Yast::SuSEFirewall, :GetModified) - end - it "returns false when no module was modified" do reset_modification_statuses expect(Yast::Lan.Modified).to be false From 9f5c9c90a74e46e31e97f1ee8c5ab9ca9438fdf8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Knut=20Alejandro=20Anderssen=20Gonz=C3=A1lez?= Date: Fri, 24 Nov 2017 12:10:18 +0000 Subject: [PATCH 6/8] Remove class as wicked will take care of fw zone changes. --- src/lib/network/firewalld_interface_zones.rb | 126 ------------------- 1 file changed, 126 deletions(-) delete mode 100644 src/lib/network/firewalld_interface_zones.rb diff --git a/src/lib/network/firewalld_interface_zones.rb b/src/lib/network/firewalld_interface_zones.rb deleted file mode 100644 index b76ccc029..000000000 --- a/src/lib/network/firewalld_interface_zones.rb +++ /dev/null @@ -1,126 +0,0 @@ -# encoding: utf-8 -# -# *************************************************************************** -# -# Copyright (c) 2017 SUSE LLC. -# All Rights Reserved. -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of version 2 or 3 of the GNU General -# Public License as published by the Free Software Foundation. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, contact SUSE LLC. -# -# To contact SUSE about this file by physical or electronic mail, -# you may find current contact information at www.suse.com -# -# *************************************************************************** - -require "yast" -require "singleton" -require "y2firewall/firewalld" - -Yast.import "NetworkInterfaces" - -module Yast - # This class is responsible of update the state of network interfaces zones - # in firewalld. - class FirewalldInterfaceZones - include Singleton - include Logger - include I18n - # Maintains the original interface zones map. - attr_accessor :original - - # Constructor - def initialize - read - end - - # Sets the current configuration as the original. - def read - @original = current - end - - # Perform in firewalld the changes between the original and current state. - def apply_changes - removed_interfaces.each { |i| remove_interface(i) } - added_interfaces.each { |i| change_interface(i) } - modified_interfaces.each { |i| change_interface(i) } - end - - # Obtain current interfaces zones. - # - # return [Hash] - def current - interface_zone = {} - - NetworkInterfaces.List("").map do |name| - interface_zone[name] = - { - id: name, - description: get_value(name, "NAME"), - zone: get_value(name, "ZONE") - } - end - - interface_zone - end - - private - - # @return [Y2Firewalld::Firewalld] singleton instance - def firewalld - Y2Firewall::Firewalld.instance - end - - # Convenience method for obtain the value of a specific network interface - # attribute. - # - # @param name [String] network interface name - # @param value [String] network interface attribute - # @return [String] the value of the given attribute - def get_value(name, attribute) - NetworkInterfaces::GetValue(name, attribute) - end - - # @return [Array] removed interface names - def removed_interfaces - original.keys - current.keys - end - - # @return [Array] added interface names - def added_interfaces - current.keys - original.keys - end - - # @return [Array] modified interface names - def modified_interfaces - current.select { |k, v| original[k] && (original[k][:zone] != v[:zone]) }.keys - end - - # Convenience method for remove an interface from a firewalld zone - def remove_interface(name) - log.info("Removing interface #{name} from its original zone #{original[name][:zone]}.") - - firewalld.api.remove_interface(original[name], original[name][:zone]) - end - - # Convenience method for change an interface to its current firewalld zone - def change_interface(name) - zone = current.fetch(name, {}).fetch(:zone, "") - if zone.empty? - remove_interface(name) if original[name] - else - log.info("Changing interface #{name} to zone #{zone}") - firewalld.api.change_interface(zone, name) - end - end - end -end From c4c67a65fbcc61eae08ef441b2238e28abf4b6c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Knut=20Alejandro=20Anderssen=20Gonz=C3=A1lez?= Date: Fri, 24 Nov 2017 12:09:30 +0000 Subject: [PATCH 7/8] Bump version & changelog. --- package/yast2-network.changes | 8 ++++++++ package/yast2-network.spec | 8 ++++---- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/package/yast2-network.changes b/package/yast2-network.changes index d2e200e59..e1ba6cd70 100644 --- a/package/yast2-network.changes +++ b/package/yast2-network.changes @@ -1,3 +1,11 @@ +------------------------------------------------------------------- +Fri Nov 24 11:57:33 UTC 2017 - knut.anderssen@suse.com + +- Do not depend on SuSEFirewall for zone interface change. The zone + is now written in the ifcfg-file and wicked takes care of calling + firewalld commandline. (fate#323460) +- 4.0.10 + ------------------------------------------------------------------- Wed Nov 22 11:59:22 UTC 2017 - knut.anderssen@suse.com diff --git a/package/yast2-network.spec b/package/yast2-network.spec index 8e3846c9e..76b9a93a0 100644 --- a/package/yast2-network.spec +++ b/package/yast2-network.spec @@ -17,7 +17,7 @@ Name: yast2-network -Version: 4.0.9 +Version: 4.0.10 Release: 0 BuildArch: noarch @@ -30,9 +30,9 @@ Requires: yast2-proxy #for install task BuildRequires: rubygem(yast-rake) -# yast2 v3.1.86: Added ServicesProposal library -BuildRequires: yast2 >= 4.0.1 -Requires: yast2 >= 4.0.1 +# yast2 v4.0.17: Y2Firewall::Firewalld::Zone.known_zones (fate#323460) +BuildRequires: yast2 >= 4.0.17 +Requires: yast2 >= 4.0.17 # Product control need xml agent BuildRequires: yast2-xml From def209eca2390b22f04687639a6a2ce989ad8948 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Knut=20Alejandro=20Anderssen=20Gonz=C3=A1lez?= Date: Fri, 24 Nov 2017 13:34:14 +0000 Subject: [PATCH 8/8] Changes based on CR. --- src/include/network/lan/address.rb | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/src/include/network/lan/address.rb b/src/include/network/lan/address.rb index 5280aa14f..5b7753fca 100644 --- a/src/include/network/lan/address.rb +++ b/src/include/network/lan/address.rb @@ -1603,10 +1603,14 @@ def initial_hostname(ipaddr) String.FirstChunk(Ops.get(host_list, 0, ""), " \t") end + # Return a list of items for ComboBox with all the known firewalld zones + # and also an empty string option for the default zone. + # + # @return [Array >] list of names an description of + # known zones def firewall_zones - @firewalld ||= Y2Firewall::Firewalld.instance zones = [["", _("Automatically Assigned Zone")]] - if @firewalld.installed? + if firewalld.installed? Y2Firewall::Firewalld::Zone.known_zones.map do |name, full_name| zones << [name, full_name] end @@ -1616,5 +1620,12 @@ def firewall_zones zones end + + # Convenience method which returns an instance of Y2Firewall::Firewalld + # + # @return [Y2Firewall::Firewalld] instance + def firewalld + @firewalld ||= Y2Firewall::Firewalld.instance + end end end