library/network/src/lib/network/susefirewall2.rb
# ***************************************************************************
#
# Copyright (c) 2002 - 2016 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
#
# ***************************************************************************
#
# Module for handling SuSEfirewall2 or FirewallD
# Package: SuSEFirewall configuration
# Summary: Interface manipulation of /etc/sysconfig/SuSEFirewall
# Authors: Lukas Ocilka <locilka@suse.cz
#
# $Id$
#
# Module for handling SuSEfirewall2
require "yast"
require "network/susefirewall"
module Yast
# ----------------------------------------------------------------------------
# SuSEFirewall2/SF2 Class. The original, simply created from the Firewall
# factory class.
class SuSEFirewall2Class < SuSEFirewallClass
CONFIG_FILE = "/etc/sysconfig/SuSEfirewall2".freeze
include Yast::Logger
def main
textdomain "base"
Yast.import "Mode"
Yast.import "Service"
Yast.import "NetworkInterfaces"
Yast.import "PortAliases"
Yast.import "Report"
Yast.import "Message"
Yast.import "Progress"
Yast.import "PortRanges"
Yast.import "FileUtils"
Yast.import "Directory"
Yast.import "Stage"
Yast.import "Pkg"
# <!-- SuSEFirewall VARIABLES //-->
@FIREWALL_PACKAGE = "SuSEfirewall2"
# configuration hasn't been read for the default
# this should reduce the readings to only ONE
@configuration_has_been_read = false
# String which includes all interfaces not-defined in any zone
@special_all_interface_string = "any"
# Maximal number of port number, they are in the interval 1-65535 included
@max_port_number = PortRanges.max_port_number
# Zone which works with the special_all_interface_string string
@special_all_interface_zone = "EXT"
# firewall settings map
@SETTINGS = {}
# configuration was modified when true
@modified = false
# defines if SuSEFirewall is running
@is_running = false
# default settings for SuSEFirewall
@DEFAULT_SETTINGS = {
"FW_LOG_ACCEPT_ALL" => "no",
"FW_LOG_ACCEPT_CRIT" => "yes",
"FW_LOG_DROP_ALL" => "no",
"FW_LOG_DROP_CRIT" => "yes",
"FW_PROTECT_FROM_INT" => "no",
"FW_ROUTE" => "no",
"FW_STOP_KEEP_ROUTING_STATE" => "no",
"FW_MASQUERADE" => "no",
"FW_ALLOW_FW_TRACEROUTE" => "yes",
"FW_ALLOW_PING_FW" => "yes",
"FW_ALLOW_FW_BROADCAST_EXT" => "no",
"FW_ALLOW_FW_BROADCAST_INT" => "no",
"FW_ALLOW_FW_BROADCAST_DMZ" => "no",
"FW_IGNORE_FW_BROADCAST_EXT" => "yes",
"FW_IGNORE_FW_BROADCAST_INT" => "no",
"FW_IGNORE_FW_BROADCAST_DMZ" => "no",
"FW_IPSEC_TRUST" => "no",
"FW_BOOT_FULL_INIT" => "no"
}
# verbose_level -> if verbosity is more than 0, be verbose, starting in verbose mode
@verbose_level = 1
# list of known firewall zones
@known_firewall_zones = ["INT", "DMZ", "EXT"]
# map defines zone name for all known firewall zones
@zone_names = {
# TRANSLATORS: Firewall zone name - used in combo box or dialog title
"EXT" => _(
"External Zone"
),
# TRANSLATORS: Firewall zone name - used in combo box or dialog title
"INT" => _(
"Internal Zone"
),
# TRANSLATORS: Firewall zone name - used in combo box or dialog title
"DMZ" => _(
"Demilitarized Zone"
)
}
# internal zone identification - useful for protect-from-internal
@int_zone_shortname = "INT"
# list of protocols supported in firewall, use only upper-cases
@supported_protocols = ["TCP", "UDP", "RPC", "IP"]
# list of keys in map of definition well-known services
@service_defined_by = [
"tcp_ports",
"udp_ports",
"rpc_ports",
"ip_protocols",
"broadcast_ports"
]
# list of services currently allowed, which share ports (for instance RPC services)
@allowed_conflict_services = {}
@firewall_service = "SuSEfirewall2"
@SuSEFirewall_variables = [
# zones and interfaces
"FW_DEV_INT",
"FW_DEV_DMZ",
"FW_DEV_EXT",
# services in zones
"FW_SERVICES_INT_TCP",
"FW_SERVICES_INT_UDP",
"FW_SERVICES_INT_RPC",
"FW_SERVICES_INT_IP",
"FW_SERVICES_DMZ_TCP",
"FW_SERVICES_DMZ_UDP",
"FW_SERVICES_DMZ_RPC",
"FW_SERVICES_DMZ_IP",
"FW_SERVICES_EXT_TCP",
"FW_SERVICES_EXT_UDP",
"FW_SERVICES_EXT_RPC",
"FW_SERVICES_EXT_IP",
"FW_PROTECT_FROM_INT",
# global routing, masquerading
"FW_ROUTE",
"FW_STOP_KEEP_ROUTING_STATE",
"FW_MASQUERADE",
"FW_FORWARD_MASQ",
"FW_FORWARD_ALWAYS_INOUT_DEV",
# broadcast packets
"FW_ALLOW_FW_BROADCAST_EXT",
"FW_ALLOW_FW_BROADCAST_INT",
"FW_ALLOW_FW_BROADCAST_DMZ",
"FW_IGNORE_FW_BROADCAST_EXT",
"FW_IGNORE_FW_BROADCAST_INT",
"FW_IGNORE_FW_BROADCAST_DMZ",
# FATE #300970: Support for 'Samba & friends' browsing
"FW_SERVICES_ACCEPT_RELATED_EXT",
"FW_SERVICES_ACCEPT_RELATED_INT",
"FW_SERVICES_ACCEPT_RELATED_DMZ",
# logging
"FW_LOG_DROP_CRIT",
"FW_LOG_DROP_ALL",
"FW_LOG_ACCEPT_CRIT",
"FW_LOG_ACCEPT_ALL",
# IPsec support
"FW_IPSEC_TRUST",
# Custom rulezz
# net,protocol[,dport][,sport]
"FW_SERVICES_ACCEPT_EXT",
"FW_SERVICES_ACCEPT_INT",
"FW_SERVICES_ACCEPT_DMZ",
# Custom kernel modules, e.g., for FTP
"FW_LOAD_MODULES",
# Services defined in /usr/share/SuSEfirewall2/services/ directory
# FATE #300687: Ports for SuSEfirewall added via packages
"FW_CONFIGURATIONS_EXT",
"FW_CONFIGURATIONS_INT",
"FW_CONFIGURATIONS_DMZ",
# bsc#916376: Ports need to be open already during boot
"FW_BOOT_FULL_INIT"
]
# FATE #300970: Firewall support for SMB browsing
@broadcast_related_module = "nf_conntrack_netbios_ns"
# Variable for ReportOnlyOnce() function
@report_only_once = []
# <!-- SuSEFirewall LOCAL FUNCTIONS //-->
# <!-- SuSEFirewall GLOBAL FUNCTIONS //-->
# bnc #388773
# By default needed packages are just checked, not installed
@check_and_install_package = false
# Are needed packages (SuSEfirewall2) installed?
@needed_packages_installed = nil
# Configuration has been read and it's useful
@fw_service_can_be_configured = false
# old internal services definitions are converted to new services defined by packages
# but only once
@converted_to_services_dbp_file = Ops.add(
Directory.vardir,
"/yast2-firewall-already-converted-to-sdbp"
)
# services have been already converted
@already_converted = false
@protocol_translations = {
# protocol name
"tcp" => _("TCP"),
# protocol name
"udp" => _("UDP"),
# protocol name
"_rpc_" => _("RPC"),
# protocol name
"ip" => _("IP")
}
end
# <!-- SuSEFirewall VARIABLES //-->
# <!-- SuSEFirewall GLOBAL FUNCTIONS USED BY LOCAL ONES //-->
# Report the error, warning, message only once.
# Stores the error, warning, message in memory.
# This is just a helper function that could avoid from filling y2log up with
# a lot of the very same messages - 'foreach()' is a very powerful builtin.
#
# @param [String] what_to_report error, warning or message
# @return [Boolean] whether the message should be reported or not
#
# @example
# string error = sformat("Port number %1 is invalid.", port_nr);
# if (ReportOnlyOnce(error)) y2error(error);
def ReportOnlyOnce(what_to_report)
return false if Builtins.contains(@report_only_once, what_to_report)
@report_only_once = Builtins.add(@report_only_once, what_to_report)
true
end
# <!-- SuSEFirewall GLOBAL FUNCTIONS USED BY LOCAL ONES //-->
# <!-- SuSEFirewall LOCAL FUNCTIONS //-->
# Function returns whether the feature 'any' network interface is supported in the
# firewall configuration. The string 'any' must be in the 'EXT' zone.
# Updated: Currently returns only 'true' as every unassigned interface is
# automatically assigned to the EXT zone by SuSEfirewall2.
#
# @return [Boolean] is_supported whether the feature is supported or not
def IsAnyNetworkInterfaceSupported
# Currently unassigned interfaces belong to the EXT zone by dafault
true
end
# Function return list of variables needed for SuSEFirewall's settings.
#
# @return [Array<String>] of names of variables
def GetListOfSuSEFirewallVariables
deep_copy(@SuSEFirewall_variables)
end
# Local function for increasing the verbosity level.
def IncreaseVerbosity
@verbose_level = Ops.add(@verbose_level, 1)
nil
end
# Local function for decreasing the verbosity level.
def DecreaseVerbosity
@verbose_level = Ops.subtract(@verbose_level, 1)
nil
end
# Local function returns if other functions should produce verbose output.
# like popups, reporting errors, etc.
#
# @return [Boolean] is_verbose
def IsVerbose
# verbose level must be above zero to be verbose
Ops.greater_than(@verbose_level, 0)
end
# Local function for returning default values (if defined) for sysconfig variables.
#
# @param [String] variable sysconfig variable
# @return [String] default value
def GetDefaultValue(variable)
Ops.get(@DEFAULT_SETTINGS, variable, "")
end
# Local function for reading list of sysconfig variables into internal variables.
#
# @param [Array<String>] variables of sysconfig variables
def ReadSysconfigSuSEFirewall(variables)
variables = deep_copy(variables)
Builtins.foreach(variables) do |variable|
value = Convert.to_string(
SCR.Read(Builtins.add(path(".sysconfig.SuSEfirewall2"), variable))
)
# if value is undefined, get default value
value = GetDefaultValue(variable) if value.nil? || value == ""
# BNC #426000
# backslash at the end
if Builtins.regexpmatch(value, "[ \t]*\\\\[ \t]*\n")
rules = Builtins.splitstring(value, "\\ \t\n")
rules = Builtins.filter(rules) do |one_rule|
!one_rule.nil? && one_rule != ""
end
value = Builtins.mergestring(rules, " ")
end
# BNC #194419
# replace all "\n" with " " in variables
value = Builtins.mergestring(Builtins.splitstring(value, "\n"), " ") if Builtins.regexpmatch(value, "\n")
# replace all "\t" with " " in variables
value = Builtins.mergestring(Builtins.splitstring(value, "\t"), " ") if Builtins.regexpmatch(value, "\t")
Ops.set(@SETTINGS, variable, value)
end
nil
end
# Local function for resetting list of sysconfig variables in internal variables.
#
# @param [Array<String>] variables of sysconfig variables
def ResetSysconfigSuSEFirewall(variables)
variables = deep_copy(variables)
Builtins.foreach(variables) do |variable|
# reseting means getting default variables
Ops.set(@SETTINGS, variable, GetDefaultValue(variable))
end
nil
end
# Local function for writing the list of internal variables into sysconfig.
# List of variables is list of keys in SETTINGS map, to sync configuration
# into the disk, use `nil` as the last list item.
#
# @param [Array<String>] variables of sysconfig variables
# @return [Boolean] if successful
def WriteSysconfigSuSEFirewall(variables)
variables = deep_copy(variables)
write_status = true
value = ""
Builtins.foreach(variables) do |variable|
# if variable is undefined, get default value
value = Ops.get_string(@SETTINGS, variable) { GetDefaultValue(variable) }
write_status = SCR.Write(
Builtins.add(path(".sysconfig.SuSEfirewall2"), variable),
value
)
if !write_status
Report.Error(
Message.CannotWriteSettingsTo("/etc/sysconfig/SuSEFirewall2")
)
raise Break
end
end
write_status = SCR.Write(path(".sysconfig.SuSEfirewall2"), nil)
if !write_status
Report.Error(
Message.CannotWriteSettingsTo("/etc/sysconfig/SuSEFirewall2")
)
end
write_status
end
# Local function returns configuration string used in configuration for zone.
# For instance "ext" for "EXT" zone.
#
# @param [String] zone shortname
# @return [String] zone configuration string
def GetZoneConfigurationString(zone)
if IsKnownZone(zone)
# zones in SuSEFirewall configuration are identified by lowercased zone shorters
return Builtins.tolower(zone)
end
nil
end
# Local function returns zone name (shortname) for configuration string.
# For instance "EXT" for "ext" zone.
#
# @param [String] zone_string configuration string
# @return [String] zone shortname
def GetConfigurationStringZone(zone_string)
if IsKnownZone(Builtins.toupper(zone_string))
# zones in SuSEFirewall configuration are identified by lowercased zone shorters
return Builtins.toupper(zone_string)
end
nil
end
# Function returns list of allowed services for zone and protocol
#
# @param [String] zone
# @param [String] protocol
# @return [Array<String>] of allowed services/ports
def GetAllowedServicesForZoneProto(zone, protocol)
Builtins.splitstring(
Ops.get_string(
@SETTINGS,
Ops.add(Ops.add(Ops.add("FW_SERVICES_", zone), "_"), protocol),
""
),
" "
)
end
# Function sets list of services as allowed ports for zone and protocol
#
# @param [Array<String>] allowed_services of allowed ports/services
# @param [String] zone
# @param [String] protocol
def SetAllowedServicesForZoneProto(allowed_services, zone, protocol)
allowed_services = deep_copy(allowed_services)
SetModified()
Ops.set(
@SETTINGS,
Ops.add(Ops.add(Ops.add("FW_SERVICES_", zone), "_"), protocol),
Builtins.mergestring(Builtins.toset(allowed_services), " ")
)
nil
end
# Local function returns configuration string for broadcast packets.
#
# @return [String] with broadcast configuration
def GetBroadcastConfiguration(zone)
Ops.get_string(@SETTINGS, Ops.add("FW_ALLOW_FW_BROADCAST_", zone), "no")
end
# Local function saves configuration string for broadcast packets.
#
# @param [String] zone
# @param [String] broadcast_configuration with broadcast configuration
def SetBroadcastConfiguration(zone, broadcast_configuration)
SetModified()
Ops.set(
@SETTINGS,
Ops.add("FW_ALLOW_FW_BROADCAST_", zone),
broadcast_configuration
)
nil
end
# Local function returns map of allowed ports (without aliases).
# If any list for zone is defined but empty, all allowed
# UDP ports for this zone also accept broadcast packets.
# This function returns only ports that are mentioned in configuration,
# it doesn't return ports that are listed in some service (defined by package)
# which is enabled.
#
# @return [Hash{String => Array<String>}] strings are allowed ports or port ranges
#
#
# **Structure:**
#
# $[
# "ZONE1" : [ "port1", "port2" ],
# "ZONE2" : [ "port3", "port4" ],
# "ZONE3" : [ ]
# ]
# or
# $[
# "ZONE1" : [ "yes" ], // will work for all ports automatically
# "ZONE3" : [ ],
# "ZONE3" : [ ]
# ]
def GetBroadcastAllowedPorts
allowed_ports = {}
Builtins.foreach(GetKnownFirewallZones()) do |zone|
broadcast = GetBroadcastConfiguration(zone)
# no broadcast allowed for this zone
case broadcast
when "no"
Ops.set(allowed_ports, zone, [])
# BNC #694782: "yes" is automatically translated by SuSEfirewall2
when "yes"
Ops.set(allowed_ports, zone, ["yes"])
# only listed ports allow broadcast
else
Ops.set(allowed_ports, zone, Builtins.splitstring(broadcast, " "))
Ops.set(
allowed_ports,
zone,
Builtins.filter(Builtins.splitstring(broadcast, " ")) do |not_space|
not_space != ""
end
)
end
end
Builtins.y2debug("Allowed Broadcast Ports: %1", allowed_ports)
deep_copy(allowed_ports)
end
# Function creates allowed-broadcast-ports string from broadcast map and saves it.
#
# @param [Hash<String,Array<String>>] broadcast strings are allowed ports or port ranges
# @see GetBroadcastAllowedPorts() for an example of data
def SetBroadcastAllowedPorts(broadcast)
broadcast = deep_copy(broadcast)
SetModified()
Builtins.foreach(GetKnownFirewallZones()) do |zone|
Ops.set(broadcast, zone, ["no"]) if Ops.get(broadcast, zone, []) == []
SetBroadcastConfiguration(
zone,
Builtins.mergestring(Ops.get(broadcast, zone, []), " ")
)
end
nil
end
# Function returns if broadcast is allowed for needed ports in zone.
#
# @param [Array<String>] needed_ports
# @param [String] zone
# @return [Boolean] if is allowed
#
# @example
# IsBroadcastAllowed (["port-xyz", "53"], "EXT") -> true
def IsBroadcastAllowed(needed_ports, zone)
needed_ports = deep_copy(needed_ports)
if Builtins.size(needed_ports) == 0
Builtins.y2warning("Unknown service with no needed ports!")
return nil
end
# getting broadcast allowed ports
allowed_ports_map = GetBroadcastAllowedPorts()
# Divide allowed port ranges and aliases (also with their port aliases)
allowed_ports_divided = PortRanges.DividePortsAndPortRanges(
Ops.get(allowed_ports_map, zone, []),
true
)
# If there are no allowed ports at all
if Ops.get(allowed_ports_divided, "ports", []) == [] &&
Ops.get(allowed_ports_divided, "port_ranges", []) == []
return false
end
is_allowed = true
# checking all needed ports;
Builtins.foreach(needed_ports) do |needed_port|
# allowed ports don't contain the needed one and also portranges don't
if !Builtins.contains(
Ops.get(allowed_ports_divided, "ports", []),
needed_port
) &&
!PortRanges.PortIsInPortranges(
needed_port,
Ops.get(allowed_ports_divided, "port_ranges", [])
)
is_allowed = false
raise Break
end
end
is_allowed
end
# Local function removes list of ports from port allowing broadcast packets in zone.
#
# @param [Array<String>] needed_ports to be removed
# @param [String] zone
def RemoveAllowedBroadcast(needed_ports, zone)
needed_ports = deep_copy(needed_ports)
SetModified()
allowed_ports = GetBroadcastAllowedPorts()
list_ports_allowed = Ops.get(allowed_ports, zone, [])
# ports to be allowed one by one
Builtins.foreach(needed_ports) do |allow_this_port|
# remove all aliases of ports yet mentioned in zone
aliases_of_port = PortAliases.GetListOfServiceAliases(allow_this_port)
list_ports_allowed = Builtins.filter(list_ports_allowed) do |just_allowed|
!Builtins.contains(aliases_of_port, just_allowed)
end
end
Ops.set(allowed_ports, zone, list_ports_allowed)
# save it using function
SetBroadcastAllowedPorts(allowed_ports)
nil
end
# Local function adds list of ports to ports accepting broadcast
#
# @param [Array<String>] needed_ports of ports
# @param [String] zone
def AddAllowedBroadcast(needed_ports, zone)
needed_ports = deep_copy(needed_ports)
# changing only if ports are not allowed
if !IsBroadcastAllowed(needed_ports, zone)
SetModified()
allowed_ports = GetBroadcastAllowedPorts()
list_ports_allowed = Ops.get(allowed_ports, zone, [])
# ports to be allowed one by one
Builtins.foreach(needed_ports) do |allow_this_port|
# at first: remove all aliases of ports yet mentioned in zone
aliases_of_port = PortAliases.GetListOfServiceAliases(allow_this_port)
list_ports_allowed = Builtins.filter(list_ports_allowed) do |just_allowed|
!Builtins.contains(aliases_of_port, just_allowed)
end
# at second: add only one
list_ports_allowed = Builtins.add(list_ports_allowed, allow_this_port)
end
Ops.set(allowed_ports, zone, list_ports_allowed)
# save it using function
SetBroadcastAllowedPorts(allowed_ports)
end
nil
end
# Local function for removing (disallowing) single service/port
# for defined protocol and zone. Functions doesn't take care of
# port-aliases.
#
# @param [String] remove_service service/port
# @param [String] protocol
# @param [String] zone
# @return [Boolean] success
def RemoveServiceFromProtocolZone(remove_service, protocol, zone)
SetModified()
key = Ops.add(Ops.add(Ops.add("FW_SERVICES_", zone), "_"), protocol)
allowed = Builtins.splitstring(Ops.get_string(@SETTINGS, key, ""), " ")
allowed = Builtins.filter(allowed) do |single_service|
single_service != "" && single_service != remove_service
end
Ops.set(
@SETTINGS,
key,
Builtins.mergestring(Builtins.toset(allowed), " ")
)
true
end
# Removes service defined by package (FATE #300687) from enabled services.
#
# @param [String] service
# @param [String] zone
#
# @example
# RemoveServiceDefinedByPackageFromZone ("service:irc-server", "EXT");
def RemoveServiceDefinedByPackageFromZone(service, zone)
return nil if !IsKnownZone(zone)
if service.nil?
Builtins.y2error("Service Id can't be nil!")
return nil
elsif Builtins.regexpmatch(service, "^service:.*")
service = Builtins.regexpsub(service, "^service:(.*)", "\\1")
end
# services defined by package are listed without "service:" which is here
# just to distinguish between dynamic and static definitions
supported_services = Builtins.splitstring(
Ops.get_string(@SETTINGS, Ops.add("FW_CONFIGURATIONS_", zone), ""),
" "
)
# Removing the service
supported_services = Builtins.filter(supported_services) do |one_service|
one_service != service
end
Ops.set(
@SETTINGS,
Ops.add("FW_CONFIGURATIONS_", zone),
Builtins.mergestring(supported_services, " ")
)
SetModified()
nil
end
# Adds service defined by package (FATE #300687) into list of enabled services.
#
# @param [String] service
# @param [String] zone
#
# @example
# AddServiceDefinedByPackageIntoZone ("service:irc-server", "EXT");
def AddServiceDefinedByPackageIntoZone(service, zone)
return nil if !IsKnownZone(zone)
if service.nil?
Builtins.y2error("Service Id can't be nil!")
return nil
elsif Builtins.regexpmatch(service, "^service:.*")
service = Builtins.regexpsub(service, "^service:(.*)", "\\1")
end
# services defined by package are listed without "service:" which is here
# just to distinguish between dynamic and static definitions
supported_services = Builtins.splitstring(
Ops.get_string(@SETTINGS, Ops.add("FW_CONFIGURATIONS_", zone), ""),
" "
)
# Adding the service
supported_services = Builtins.toset(
Builtins.add(supported_services, service)
)
Ops.set(
@SETTINGS,
Ops.add("FW_CONFIGURATIONS_", zone),
Builtins.mergestring(supported_services, " ")
)
SetModified()
nil
end
# Local function removes well-known service's support from zone.
# Allowed ports are removed with all of their port-aliases.
#
# @param [String] service id
# @param [String] zone
def RemoveServiceSupportFromZone(service, zone)
Yast.import "SuSEFirewallServices" # lazy import due to circular dependencies
needed = SuSEFirewallServices.GetNeededPortsAndProtocols(service)
# unknown service
if needed.nil?
Builtins.y2error("Undefined service '%1'", service)
return nil
end
# FATE #300687: Ports for SuSEfirewall added via packages
if SuSEFirewallServices.ServiceDefinedByPackage(service)
RemoveServiceDefinedByPackageFromZone(service, zone) if IsServiceSupportedInZone(service, zone) == true
return nil
end
SetModified()
# Removing service ports (and also port aliases for TCP and UDP)
Builtins.foreach(@service_defined_by) do |key|
needed_ports = Ops.get(needed, key, [])
next if needed_ports == []
case key
when "tcp_ports"
RemoveAllowedPortsOrServices(needed_ports, "TCP", zone, true)
when "udp_ports"
RemoveAllowedPortsOrServices(needed_ports, "UDP", zone, true)
when "rpc_ports"
RemoveAllowedPortsOrServices(needed_ports, "RPC", zone, false)
when "ip_protocols"
RemoveAllowedPortsOrServices(needed_ports, "IP", zone, false)
when "broadcast_ports"
RemoveAllowedBroadcast(needed_ports, zone)
else
Builtins.y2error("Unknown key '%1'", key)
end
end
nil
end
# Local function adds well-known service's support into zone. It first of all
# removes the current support for service with port-aliases.
#
# @param [String] service id
# @param [String] zone
def AddServiceSupportIntoZone(service, zone)
Yast.import "SuSEFirewallServices" # lazy import due to circular dependencies
needed = SuSEFirewallServices.GetNeededPortsAndProtocols(service)
# unknown service
if needed.nil?
Builtins.y2error("Undefined service '%1'", service)
return nil
end
SetModified()
# FATE #300687: Ports for SuSEfirewall added via packages
if SuSEFirewallServices.ServiceDefinedByPackage(service)
AddServiceDefinedByPackageIntoZone(service, zone)
return nil
end
# Removing service ports first (and also port aliases for TCP and UDP)
RemoveServiceSupportFromZone(service, zone) if IsServiceSupportedInZone(service, zone) == true
Builtins.foreach(@service_defined_by) do |key|
needed_ports = Ops.get(needed, key, [])
next if needed_ports == []
case key
when "tcp_ports"
AddAllowedPortsOrServices(needed_ports, "TCP", zone)
when "udp_ports"
AddAllowedPortsOrServices(needed_ports, "UDP", zone)
when "rpc_ports"
AddAllowedPortsOrServices(needed_ports, "RPC", zone)
when "ip_protocols"
AddAllowedPortsOrServices(needed_ports, "IP", zone)
when "broadcast_ports"
AddAllowedBroadcast(needed_ports, zone)
else
Builtins.y2error("Unknown key '%1'", key)
end
end
nil
end
# Function resets flag which doesn't allow to read configuration from disk again.
# So you actually can reread the configuration from disk. Currently, only the first
# Read() call reads the configuration from disk.
def ResetReadFlag
@configuration_has_been_read = false
nil
end
# Function sets if firewall should be protected from internal zone.
#
# @param [Boolean] set_protect set to be protected from internal zone
def SetProtectFromInternalZone(set_protect)
SetModified()
if set_protect
Ops.set(@SETTINGS, "FW_PROTECT_FROM_INT", "yes")
else
Ops.set(@SETTINGS, "FW_PROTECT_FROM_INT", "no")
end
nil
end
# Function returns if firewall is protected from internal zone.
#
# @return [Boolean] if protected from internal
def GetProtectFromInternalZone
Ops.get_string(@SETTINGS, "FW_PROTECT_FROM_INT", "no") == "yes"
end
# Function sets if firewall should support routing.
#
# @param [Boolean] set_route set to support route or not
def SetSupportRoute(set_route)
SetModified()
if set_route
Ops.set(@SETTINGS, "FW_STOP_KEEP_ROUTING_STATE", "yes")
Ops.set(@SETTINGS, "FW_ROUTE", "yes")
else
Ops.set(@SETTINGS, "FW_STOP_KEEP_ROUTING_STATE", "no")
Ops.set(@SETTINGS, "FW_ROUTE", "no")
end
nil
end
# Function returns if firewall supports routing.
#
# @return [Boolean] if route is supported
def GetSupportRoute
Ops.get_string(@SETTINGS, "FW_ROUTE", "no") == "yes"
end
# Function sets how firewall should trust successfully decrypted IPsec packets.
# It should be the zone name (shortname) or 'no' to trust packets the same as
# firewall trusts the zone from which IPsec packet came.
#
# @param [String] zone or "no"
def SetTrustIPsecAs(zone)
SetModified()
# do not trust
if zone == "no"
Ops.set(@SETTINGS, "FW_IPSEC_TRUST", "no")
# trust IPsec is a known zone
elsif IsKnownZone(zone)
zone = GetZoneConfigurationString(zone)
Ops.set(@SETTINGS, "FW_IPSEC_TRUST", zone)
# unknown zone, changing to default value
else
defaultv = GetDefaultValue("FW_IPSEC_TRUST")
Builtins.y2warning(
"Trust IPsec as '%1' (unknown zone) changed to '%2'",
zone,
defaultv
)
Ops.set(@SETTINGS, "FW_IPSEC_TRUST", defaultv)
end
nil
end
# Function returns the trust level of IPsec packets.
# See SetTrustIPsecAs() for more information.
#
# @return [String] zone or "no"
def GetTrustIPsecAs
# do not trust
return "no" if Ops.get(@SETTINGS, "FW_IPSEC_TRUST") == "no"
# default value for 'yes" ~= "INT"
return "INT" if Ops.get(@SETTINGS, "FW_IPSEC_TRUST") == "yes"
zone = GetConfigurationStringZone(
Ops.get_string(@SETTINGS, "FW_IPSEC_TRUST", "")
)
# trust as named zone (if known)
return zone if IsKnownZone(zone)
# unknown zone, change to default value
SetModified()
defaultv = GetDefaultValue("FW_IPSEC_TRUST")
Builtins.y2warning(
"Trust IPsec as '%1' (unknown zone) changed to '%2'",
Ops.get_string(@SETTINGS, "FW_IPSEC_TRUST", ""),
defaultv
)
SetTrustIPsecAs(defaultv)
"no"
end
# Function for getting exported SuSEFirewall configuration
#
# @return [Hash{String => Object}] with configuration
def Export
deep_copy(@SETTINGS)
end
# Function for setting SuSEFirewall configuration from input
#
# @param [Hash<String, Object>] import_settings with configuration
def Import(import_settings)
Read()
@SETTINGS.merge!(import_settings || {})
@configuration_has_been_read = true
SetModified()
nil
end
# Function returns if the interface is in zone.
#
# @param [String] interface
# @param [String] zone firewall zone
# @return [Boolean] is in zone
#
# @example IsInterfaceInZone ("eth-id-01:11:DA:9C:8A:2F", "INT") -> false
def IsInterfaceInZone(interface, zone)
interfaces = Builtins.splitstring(
Ops.get_string(@SETTINGS, Ops.add("FW_DEV_", zone), ""),
" "
)
Builtins.contains(interfaces, interface)
end
# Function returns the firewall zone of interface, nil if no zone includes
# the interface. Error is reported when interface is found in multiple
# firewall zones, then the first appearance is returned.
#
# @param [String] interface
# @return [String] zone
#
# @example GetZoneOfInterface ("eth-id-01:11:DA:9C:8A:2F") -> "DMZ"
def GetZoneOfInterface(interface)
interface_zone = []
Builtins.foreach(GetKnownFirewallZones()) do |zone|
interface_zone = Builtins.add(interface_zone, zone) if IsInterfaceInZone(interface, zone)
end
# Fallback handling for 'any' in the FW_DEV_* configuration
if interface == @special_all_interface_string &&
Builtins.size(interface_zone) == 0
interface_zone = [@special_all_interface_zone]
end
if IsVerbose() && Ops.greater_than(Builtins.size(interface_zone), 1)
# TRANSLATORS: Error message, %1 = interface name (like eth0)
Report.Error(
Builtins.sformat(
_(
"Interface '%1' is included in multiple firewall zones.\n" \
"Continuing with configuration can produce errors.\n" \
"\n" \
"It is recommended to leave the configuration and repair it manually in\n" \
"the file '/etc/sysconfig/SuSEFirewall'."
),
interface
)
)
end
# return the first existence of interface in zones
# if it is not presented anywhere, nil is returned
Ops.get_string(interface_zone, 0)
end
# Function returns list of zones of requested interfaces.
# Special string 'any' in 'EXT' zone is supported.
#
# @param [Array<String>] interfaces
# @return [Array<String>] firewall zones
#
# @example
# GetZonesOfInterfaces (["eth1","eth4"]) -> ["EXT"]
def GetZonesOfInterfacesWithAnyFeatureSupported(interfaces)
interfaces = deep_copy(interfaces)
zones = []
zone = ""
# 'any' in 'EXT'
interfaces_covered_by_any = GetInterfacesInZoneSupportingAnyFeature(
@special_all_interface_zone
)
Builtins.foreach(interfaces) do |interface|
# interface is covered by 'any' in 'EXT'
zone = if Builtins.contains(interfaces_covered_by_any, interface)
@special_all_interface_zone
else
# interface is explicitely mentioned in some zone
GetZoneOfInterface(interface)
end
zones = Builtins.add(zones, zone) if !zone.nil?
end
Builtins.toset(zones)
end
# Function returns list of non-dial-up interfaces.
#
# @return [Array<String>] of non-dial-up interface names
# @example GetAllNonDialUpInterfaces() -> ["eth1", "eth2"]
def GetAllNonDialUpInterfaces
non_dial_up_interfaces = []
Builtins.foreach(GetAllKnownInterfaces()) do |interface|
if Ops.get(interface, "type") != "dial_up"
non_dial_up_interfaces = Builtins.add(
non_dial_up_interfaces,
Ops.get(interface, "id", "")
)
end
end
deep_copy(non_dial_up_interfaces)
end
# Function returns list of dial-up interfaces.
#
# @return [Array<String>] of dial-up interface names
# @example GetAllDialUpInterfaces() -> ["modem0", "dsl5"]
def GetAllDialUpInterfaces
dial_up_interfaces = []
Builtins.foreach(GetAllKnownInterfaces()) do |interface|
if Ops.get(interface, "type") == "dial_up"
dial_up_interfaces = Builtins.add(
dial_up_interfaces,
Ops.get(interface, "id", "")
)
end
end
deep_copy(dial_up_interfaces)
end
# Function removes interface from defined zone.
#
# @param [String] interface
# @param [String] zone
# @example RemoveInterfaceFromZone ("modem0", "EXT")
def RemoveInterfaceFromZone(interface, zone)
SetModified()
Builtins.y2milestone(
"Removing interface '%1' from '%2' zone.",
interface,
zone
)
interfaces_in_zone = Builtins.splitstring(
Ops.get_string(@SETTINGS, Ops.add("FW_DEV_", zone), ""),
" "
)
interfaces_in_zone = Builtins.filter(interfaces_in_zone) do |single_interface|
single_interface != "" && single_interface != interface
end
Ops.set(
@SETTINGS,
Ops.add("FW_DEV_", zone),
Builtins.mergestring(interfaces_in_zone, " ")
)
nil
end
# Functions adds interface into defined zone.
# All appearances of interface in other zones are removed.
#
# @param [String] interface
# @param [String] zone
# @example AddInterfaceIntoZone ("eth5", "DMZ")
def AddInterfaceIntoZone(interface, zone)
SetModified()
current_zone = GetZoneOfInterface(interface)
DecreaseVerbosity()
# removing all appearances of interface in zones, excepting current_zone==new_zone
while !current_zone.nil? && current_zone != zone
# interface is in any zone already, removing it at first
RemoveInterfaceFromZone(interface, current_zone) if current_zone != zone
current_zone = GetZoneOfInterface(interface)
end
IncreaseVerbosity()
Builtins.y2milestone(
"Adding interface '%1' into '%2' zone.",
interface,
zone
)
interfaces_in_zone = Builtins.splitstring(
Ops.get_string(@SETTINGS, Ops.add("FW_DEV_", zone), ""),
" "
)
interfaces_in_zone = Builtins.toset(
Builtins.add(interfaces_in_zone, interface)
)
Ops.set(
@SETTINGS,
Ops.add("FW_DEV_", zone),
Builtins.mergestring(interfaces_in_zone, " ")
)
nil
end
# Function returns list of known interfaces in requested zone.
# Special strings like 'any' or 'auto' and unknown interfaces are removed from list.
#
# @param [String] zone
# @return [Array<String>] of interfaces
# @example GetInterfacesInZone ("DMZ") -> ["eth4", "eth5"]
def GetInterfacesInZone(zone)
interfaces_in_zone = Builtins.splitstring(
Ops.get_string(@SETTINGS, Ops.add("FW_DEV_", zone), ""),
" "
)
known_interfaces_now = GetListOfKnownInterfaces()
# filtering special strings
interfaces_in_zone = Builtins.filter(interfaces_in_zone) do |interface|
interface != "" && Builtins.contains(known_interfaces_now, interface)
end
deep_copy(interfaces_in_zone)
end
# Function returns all interfaces already configured in firewall.
#
# @return [Array<String>] of configured interfaces
def GetFirewallInterfaces
firewall_configured_devices = []
Builtins.foreach(GetKnownFirewallZones()) do |zone|
firewall_configured_devices = Convert.convert(
Builtins.union(firewall_configured_devices, GetInterfacesInZone(zone)),
from: "list",
to: "list <string>"
)
end
Builtins.toset(firewall_configured_devices)
end
# Returns list of interfaces not mentioned in any zone and covered by the
# special string 'any' in zone 'EXT' if such string exists there and the zone
# is EXT. If the feature 'any' is not set, function returns empty list.
#
# @param [String] zone
# @return [Array<String>] of interfaces covered by special string 'any'
# @see #IsAnyNetworkInterfaceSupported()
def InterfacesSupportedByAnyFeature(zone)
result = []
if zone == @special_all_interface_zone && IsAnyNetworkInterfaceSupported()
known_interfaces_now = GetListOfKnownInterfaces()
configured_interfaces = GetFirewallInterfaces()
Builtins.foreach(known_interfaces_now) do |one_interface|
if !Builtins.contains(configured_interfaces, one_interface)
Builtins.y2milestone(
"Interface '%1' supported by special string '%2' in zone '%3'",
one_interface,
@special_all_interface_string,
@special_all_interface_zone
)
result = Builtins.add(result, one_interface)
end
end
end
deep_copy(result)
end
# Function returns list of known interfaces in requested zone.
# Special string 'any' in EXT zone covers all interfaces without
# any zone assignment.
#
# @param [String] zone
# @return [Array<String>] of interfaces
def GetInterfacesInZoneSupportingAnyFeature(zone)
interfaces_in_zone = GetInterfacesInZone(zone)
# 'any' in EXT zone, add all interfaces without zone to this one
interfaces_covered_by_any = InterfacesSupportedByAnyFeature(zone)
if Ops.greater_than(Builtins.size(interfaces_covered_by_any), 0)
interfaces_in_zone = Convert.convert(
Builtins.union(interfaces_in_zone, interfaces_covered_by_any),
from: "list",
to: "list <string>"
)
end
deep_copy(interfaces_in_zone)
end
# Returns whether a service is mentioned in FW_CONFIGURATIONS_[EXT|INT|DMZ].
# These services are defined by random packages.
#
# @param [String] service e.g., "service:sshd"
# @param [String] zone e.g., "EXT"
# @return [Boolean] if service is supported in zone
#
# @example
# IsServiceDefinedByPackageSupportedInZone ("service:sshd", "EXT") -> true
def IsServiceDefinedByPackageSupportedInZone(service, zone)
return nil if !IsKnownZone(zone)
if service.nil?
Builtins.y2error("Service Id can't be nil!")
return nil
elsif Builtins.regexpmatch(service, "^service:.*")
service = Builtins.regexpsub(service, "^service:(.*)", "\\1")
end
# services defined by package are listed without "service:" which is here
# just to distinguish between dynamic and static definitions
supported_services = Builtins.splitstring(
Ops.get_string(@SETTINGS, Ops.add("FW_CONFIGURATIONS_", zone), ""),
" "
)
Builtins.contains(supported_services, service)
end
# Function returns if service is supported (allowed) in zone. Service must be defined
# in the SuSEFirewallServices. Works transparently also with services defined by packages.
# Such service starts with "service:" prefix.
#
# @see YCP Module SuSEFirewallServices
# @param [String] service id
# @param [String] zone
# @return [Boolean] if supported
#
# @example
# // All ports defined by dns-server service in SuSEFirewallServices module
# // are enabled in the respective zone
# IsServiceSupportedInZone ("dns-server", "EXT") -> true
# // irc-server definition exists on the system and the irc-server
# // is mentioned in FW_CONFIGURATIONS_EXT variable of SuSEfirewall2
# IsServiceSupportedInZone ("service:irc-server", "EXT") -> true
def IsServiceSupportedInZone(service, zone)
return nil if !IsKnownZone(zone)
Yast.import "SuSEFirewallServices" # lazy import due to circular dependencies
needed = SuSEFirewallServices.GetNeededPortsAndProtocols(service)
# SuSEFirewall feature FW_PROTECT_FROM_INT
# should not be protected and searched zones include also internal (or the zone IS internal, sure)
if zone == @int_zone_shortname && !GetProtectFromInternalZone()
Builtins.y2milestone(
"Checking for service '%1', in '%2', PROTECT_FROM_INTERNAL='no' => allowed",
service,
zone
)
return true
end
# FATE #300687: Ports for SuSEfirewall added via packages
if SuSEFirewallServices.ServiceDefinedByPackage(service)
supported = IsServiceDefinedByPackageSupportedInZone(service, zone)
return supported
end
# starting with nil value, any false means that the service is not supported
service_is_supported = nil
Builtins.foreach(@service_defined_by) do |key|
needed_ports = Ops.get(needed, key, [])
next if needed_ports == []
case key
when "tcp_ports"
service_is_supported = ArePortsOrServicesAllowed(
needed_ports,
"TCP",
zone,
true
)
when "udp_ports"
service_is_supported = ArePortsOrServicesAllowed(
needed_ports,
"UDP",
zone,
true
)
when "rpc_ports"
service_is_supported = ArePortsOrServicesAllowed(
needed_ports,
"RPC",
zone,
false
)
when "ip_protocols"
service_is_supported = ArePortsOrServicesAllowed(
needed_ports,
"IP",
zone,
false
)
when "broadcast_ports"
# testing for allowed broadcast ports
service_is_supported = IsBroadcastAllowed(needed_ports, zone)
else
Builtins.y2error("Unknown key '%1'", key)
end
# service is not supported, we don't have to do more tests
raise Break if service_is_supported == false
end
service_is_supported
end
# Function sets status for several services in several firewall zones.
#
# @param [Array<String>] services_ids
# @param [Array<String>] firewall_zones (EXT|INT|DMZ...)
# @param [Boolean] new_status of services
# @return nil
#
# @example
# SetServicesForZones (["samba-server", "service:irc-server"], ["DMZ", "EXT"], false);
# SetServicesForZones (["samba-server", "service:irc-server"], ["EXT", "DMZ"], true);
#
# @see #GetServicesInZones()
# @see #GetServices()
def SetServicesForZones(services_ids, firewall_zones, new_status)
# setting for each service
Builtins.foreach(services_ids) do |service_id|
Builtins.foreach(firewall_zones) do |firewall_zone|
# zone must be known one
if !IsKnownZone(firewall_zone)
Builtins.y2error(
"Zone '%1' is unknown firewall zone, skipping...",
firewall_zone
)
next
end
SetModified()
# setting new status
if new_status == true
Builtins.y2milestone(
"Adding '%1' into '%2' zone",
service_id,
firewall_zone
)
AddServiceSupportIntoZone(service_id, firewall_zone)
else
Builtins.y2milestone(
"Removing '%1' from '%2' zone",
service_id,
firewall_zone
)
RemoveServiceSupportFromZone(service_id, firewall_zone)
end
end
end
nil
end
# Local function sets the default configuration and fills internal values.
def ReadDefaultConfiguration
@SETTINGS = {}
ResetSysconfigSuSEFirewall(GetListOfSuSEFirewallVariables())
nil
end
# Local function reads current configuration and fills internal values.
def ReadCurrentConfiguration
@SETTINGS = {}
# is firewall enabled in /etc/init.d/ ?
Ops.set(@SETTINGS, "enable_firewall", IsEnabled())
# is firewall started now?
Ops.set(@SETTINGS, "start_firewall", IsStarted())
ReadSysconfigSuSEFirewall(GetListOfSuSEFirewallVariables())
nil
end
# Fills the configuration with default settings,
# adjusts internal variables that firewall cannot be configured.
def FillUpEmptyConfig
# do not call it again
@configuration_has_been_read = true
# Default settings, services are disabled
@SETTINGS = deep_copy(@DEFAULT_SETTINGS)
Ops.set(@SETTINGS, "enable_firewall", false)
Ops.set(@SETTINGS, "start_firewall", false)
# Cannot be configured, packages weren't installed
@fw_service_can_be_configured = false
nil
end
# Function for reading SuSEFirewall configuration.
# Fills internal variables only.
#
# @return [Boolean] if successful
def Read
# Do not read it again and again
# to avoid rewriting changes already made
if @configuration_has_been_read
Builtins.y2milestone(
"SuSEfirewall2 configuration has been read already."
)
return @fw_service_can_be_configured
end
# bnc #887406
if !FileUtils.Exists(CONFIG_FILE) || !SuSEFirewallIsSelectedOrInstalled()
log.warn "No firewall config -> firewall can't be read"
FillUpEmptyConfig()
return false
end
# Can be configured, packages were installed
@fw_service_can_be_configured = true
# Progress only for normal configuration
have_progress = Mode.normal
if have_progress
# TRANSLATORS: Dialog caption
read_caption = _("Initializing Firewall Configuration")
Progress.New(
read_caption,
" ",
3,
[
# TRANSLATORS: Progress step
_("Check for network devices"),
# TRANSLATORS: Progress step
_("Read current configuration"),
# TRANSLATORS: Progress step
_("Check possibly conflicting services")
],
[
# TRANSLATORS: Progress step
_("Checking for network devices..."),
# TRANSLATORS: Progress step
_("Reading current configuration..."),
# TRANSLATORS: Progress step
_("Checking possibly conflicting services..."),
Message.Finished
],
""
)
Progress.NextStage
end
# Always call NI::Read, bnc #396646
NetworkInterfaces.Read
Progress.NextStage if have_progress
ReadCurrentConfiguration()
Progress.NextStage if have_progress
# checking if any possibly conficting services were turned on in configuration
# filling internal values for later checkings
# CheckAllPossiblyConflictingServices();
# -- Function has been turned off as we don't support services defined by YaST itself anymore --
Builtins.y2milestone(
"Firewall configuration has been read: %1.",
@SETTINGS
)
# to read configuration only once
@configuration_has_been_read = true
Progress.NextStage if have_progress
# bnc #399217
# Converting built-in service definitions to services defined by packages
ConvertToServicesDefinedByPackages()
Progress.Finish if have_progress
true
end
# Function returns whether some RPC service is allowed in the configuration.
# These services reallocate their ports when restarted. See details in
# bugzilla bug #186186.
#
# @return [Boolean] some_RPC_service_used
def AnyRPCServiceInConfiguration
ret = false
Builtins.foreach(GetKnownFirewallZones()) do |fw_zone|
fw_rule = Builtins.sformat("FW_SERVICES_%1_RPC", fw_zone)
listed_services = Ops.get_string(@SETTINGS, fw_rule) do
GetDefaultValue(fw_rule)
end
# easy case
next if listed_services.nil? || listed_services == ""
# something listed but it still might be empty definition
services_list = Builtins.splitstring(listed_services, " \n\t")
services_list = Builtins.filter(services_list) do |service|
service != ""
end
if Ops.greater_than(Builtins.size(services_list), 0)
ret = true
raise Break
end
end
Builtins.y2milestone("Some RPC service found: %1", ret)
ret
end
# Function which stops firewall. Then firewall is started immediately when firewall
# is wanted to be started: SetStartService(boolean).
#
# @return [Boolean] if successful
def ActivateConfiguration
# just disabled
return true if !SuSEFirewallIsInstalled()
# starting firewall during second stage can cause deadlock in systemd - bnc#798620
# Moreover, it is not needed. Firewall gets started via dependency on multi-user.target
# when second stage is over.
if Mode.installation && !Mode.autoinst
Builtins.y2milestone("Do not touch firewall services during installation")
return true
end
# Firewall should start after Write()
if GetStartService()
# Not started - start it
if !IsStarted()
Builtins.y2milestone("Starting firewall services")
StartServices()
# Started - restart it
# modified - restart it, or ...
# bugzilla #186186
# If any RPC service is configured to be allowed, always restart the firewall
# Some of these service's ports might have been reallocated (when SuSEFirewall
# is used from outside, e.g., yast2-nfs-server)
elsif GetModified() || AnyRPCServiceInConfiguration()
Builtins.y2milestone("Stopping firewall services")
StopServices()
Builtins.y2milestone("Starting firewall services")
StartServices()
# not modified - skip restart
else
Builtins.y2milestone(
"Configuration hasn't modified, skipping restarting services"
)
true
end
# Firewall should stop after Write()
# started - stop
elsif IsStarted()
Builtins.y2milestone("Stopping firewall services")
StopServices()
# stopped - skip stopping
else
Builtins.y2milestone("Firewall has been stopped already")
true
end
end
# Function writes configuration into /etc/sysconfig/ and enables or disables
# firewall in /etc/init.d/ by the setting SetEnableService(boolean).
# This is a write-only configuration, firewall is never started only enabled
# or disabled.
#
# @return [Boolean] if successful
def WriteConfiguration
# just disabled
return true if !SuSEFirewallIsInstalled()
# Progress only for normal configuration and command line
have_progress = Mode.normal
if have_progress
# TRANSLATORS: Dialog caption
write_caption = _("Writing Firewall Configuration")
Progress.New(
write_caption,
" ",
2,
[
# TRANSLATORS: Progress step
_("Write firewall settings"),
# TRANSLATORS: Progress step
_("Adjust firewall service")
],
[
# TRANSLATORS: Progress step
_("Writing firewall settings..."),
# TRANSLATORS: Progress step
_("Adjusting firewall service..."),
# TRANSLATORS: Progress step
Message.Finished
],
""
)
Progress.NextStage
end
# only modified configuration is written
if GetModified()
Builtins.y2milestone(
"Firewall configuration has been changed. Writing: %1.",
@SETTINGS
)
if !WriteSysconfigSuSEFirewall(GetListOfSuSEFirewallVariables())
# TRANSLATORS: a popup error message
Report.Error(_("Writing settings failed"))
return false
end
else
Builtins.y2milestone("Firewall settings weren't modified, skipping...")
end
Progress.NextStage if have_progress
# Adjusting services
if GetModified()
# enabling firewall in /etc/init.d/
if Ops.get_boolean(@SETTINGS, "enable_firewall", false)
Builtins.y2milestone("Enabling firewall services")
return false if !EnableServices()
# disabling firewall in /etc/init.d/
else
Builtins.y2milestone("Disabling firewall services")
return false if !DisableServices()
end
else
Builtins.y2milestone(
"Firewall enable/disable wasn't modified, skipping..."
)
end
Progress.NextStage if have_progress
if @already_converted &&
!FileUtils.Exists(@converted_to_services_dbp_file)
Builtins.y2milestone(
"Writing %1: %2",
@converted_to_services_dbp_file,
SCR.Write(path(".target.string"), @converted_to_services_dbp_file, "")
)
end
Progress.Finish if have_progress
true
end
# Helper function for backward compatibility.
# See WriteConfiguration(). Remove from code ASAP.
#
# @return [Boolean] if succesful
def WriteOnly
WriteConfiguration()
end
# Function for writing and enabling configuration, it is a union of
# WriteConfiguration() and ActivateConfiguration().
#
# @return [Boolean] if succesfull
def Write
CheckKernelModules()
# just disabled
return true if !SuSEFirewallIsInstalled()
return false if !WriteConfiguration()
return false if !ActivateConfiguration()
true
end
# This powerful function returns list of services/ports which are
# not assigned to any fully-supported known-services.
# This function doesn't check for services defined by packages.
# They are listed by a different method.
#
# @return [Array<String>] of additional (unassigned) services
#
# @example
# GetAdditionalServices("TCP", "EXT") -> ["53", "128"]
def GetAdditionalServices(protocol, zone)
if !IsSupportedProtocol(protocol)
Builtins.y2error("Unknown protocol '%1'", protocol)
return nil
end
if !IsKnownZone(zone)
Builtins.y2error("Unknown zone '%1'", zone)
return nil
end
# all ports or services allowed in zone for protocol
all_allowed_services = GetAllowedServicesForZoneProto(zone, protocol)
# all ports or services used by known service
all_used_services = []
Yast.import "SuSEFirewallServices" # lazy import due to circular dependencies
# trying all possible (known) services
Builtins.foreach(SuSEFirewallServices.GetSupportedServices) do |service_id, _service_name|
# only when the service is allowed in zone - remove all its needed ports
if IsServiceSupportedInZone(service_id, zone) == true
# all needed ports etc for service/protocol
needed_all = []
case protocol
when "TCP"
needed_all = SuSEFirewallServices.GetNeededTCPPorts(service_id)
when "UDP"
needed_all = SuSEFirewallServices.GetNeededUDPPorts(service_id)
when "RPC"
needed_all = SuSEFirewallServices.GetNeededRPCPorts(service_id)
when "IP"
needed_all = SuSEFirewallServices.GetNeededIPProtocols(service_id)
end
Builtins.foreach(needed_all) do |remove_port|
# all used services and their aliases
all_used_services = Convert.convert(
Builtins.union(
all_used_services,
PortAliases.GetListOfServiceAliases(remove_port)
),
from: "list",
to: "list <string>"
)
end
end
end
# some services are used by known defined-services
if Ops.greater_than(Builtins.size(all_used_services), 0)
all_used_services = Builtins.toset(all_used_services)
# removing all used services from all allowed
all_allowed_services = Builtins.filter(all_allowed_services) do |port|
!Builtins.contains(all_used_services, port)
end
end
# well, actually it returns list of services not-assigned to any well-known service
deep_copy(all_allowed_services)
end
# Function returns map of `interfaces in zones`.
#
# @return [Hash{String => Array<String>}] interface in zones
#
#
# **Structure:**
#
# map $[zone : [list of interfaces]]
#
# @example
# GetFirewallInterfacesMap() -> $["DMZ":[], "EXT":["dsl0"], "INT":["eth1", "eth2"]]
def GetFirewallInterfacesMap
firewall_interfaces_now = {}
# list of all known interfaces
known_interfaces = GetListOfKnownInterfaces()
# searching each zone
Builtins.foreach(GetKnownFirewallZones()) do |zone|
# filtering non-existing interfaces
Ops.set(
firewall_interfaces_now,
zone,
Builtins.filter(GetInterfacesInZone(zone)) do |interface|
Builtins.contains(known_interfaces, interface)
end
)
end
deep_copy(firewall_interfaces_now)
end
# Function returns list of special strings like 'any' or 'auto' and uknown interfaces.
#
# @param [String] zone
# @return [Array<String>] special strings or unknown interfaces
#
# @example
# GetSpecialInterfacesInZone("EXT") -> ["any", "unknown-1", "wrong-3"]
def GetSpecialInterfacesInZone(zone)
interfaces_in_zone = Builtins.splitstring(
Ops.get_string(@SETTINGS, Ops.add("FW_DEV_", zone), ""),
" "
)
known_interfaces_now = GetInterfacesInZone(zone)
# filtering known interfaces and spaces
interfaces_in_zone = Builtins.filter(interfaces_in_zone) do |interface|
interface != "" && !Builtins.contains(known_interfaces_now, interface)
end
deep_copy(interfaces_in_zone)
end
# Function removes special string from defined zone.
#
# @param [String] interface
# @param [String] zone
def RemoveSpecialInterfaceFromZone(interface, zone)
SetModified()
Builtins.y2milestone(
"Removing special string '%1' from '%2' zone.",
interface,
zone
)
interfaces_in_zone = Builtins.splitstring(
Ops.get_string(@SETTINGS, Ops.add("FW_DEV_", zone), ""),
" "
)
interfaces_in_zone = Builtins.filter(interfaces_in_zone) do |single_interface|
single_interface != "" && single_interface != interface
end
Ops.set(
@SETTINGS,
Ops.add("FW_DEV_", zone),
Builtins.mergestring(interfaces_in_zone, " ")
)
nil
end
# Function adds special string into defined zone.
#
# @param [String] interface
# @param [String] zone
def AddSpecialInterfaceIntoZone(interface, zone)
SetModified()
Builtins.y2milestone(
"Adding special string '%1' into '%2' zone.",
interface,
zone
)
interfaces_in_zone = Builtins.splitstring(
Ops.get_string(@SETTINGS, Ops.add("FW_DEV_", zone), ""),
" "
)
interfaces_in_zone = Builtins.toset(
Builtins.add(interfaces_in_zone, interface)
)
Ops.set(
@SETTINGS,
Ops.add("FW_DEV_", zone),
Builtins.mergestring(interfaces_in_zone, " ")
)
nil
end
# Function returns actual state of Masquerading support.
#
# @param _zone Ignored
# @return [Boolean] if supported
def GetMasquerade(_zone = nil)
Ops.get_string(@SETTINGS, "FW_MASQUERADE", "no") == "yes" &&
Ops.get_string(@SETTINGS, "FW_ROUTE", "no") == "yes"
end
# Function sets Masquerade support.
#
# @param enable [Boolean] to support or not to support it
# @param _zone ignored
def SetMasquerade(enable, _zone = nil)
SetModified()
Ops.set(@SETTINGS, "FW_MASQUERADE", enable ? "yes" : "no")
# routing is needed for masquerading, but we can't switch it off when disabling masquerading
Ops.set(@SETTINGS, "FW_ROUTE", "yes") if enable
nil
end
# Function returns list of rules of forwarding ports
# to masqueraded IPs.
#
# @return [Array<Hash{String => String>}] list of rules
#
#
# **Structure:**
#
# list [$[ key: value ]]
#
# @example
# GetListOfForwardsIntoMasquerade() -> [
# $[
# "forward_to":"172.24.233.1",
# "protocol":"tcp",
# "req_ip":"192.168.0.3",
# "req_port":"355",
# "source_net":"192.168.0.0/20",
# "to_port":"533"],
# ...
# ]
def GetListOfForwardsIntoMasquerade
list_of_rules = []
Builtins.foreach(
Builtins.splitstring(
Ops.get_string(@SETTINGS, "FW_FORWARD_MASQ", ""),
" "
)
) do |forward_rule|
next if forward_rule == ""
# Format: <source network>,<ip to forward to>,<protocol>,<port>[,redirect port,[destination ip]]
fw_rul = Builtins.splitstring(forward_rule, ",")
# first four parameters has to be defined
if Ops.get(fw_rul, 0, "") == "" || Ops.get(fw_rul, 1, "") == "" ||
Ops.get(fw_rul, 2, "") == "" ||
Ops.get(fw_rul, 3, "") == ""
Builtins.y2warning(
"Wrong definition of redirect rule: '%1', part of '%2'",
forward_rule,
Ops.get_string(@SETTINGS, "FW_FORWARD_MASQ", "")
)
end
list_of_rules = Builtins.add(
list_of_rules,
"source_net" => Ops.get(fw_rul, 0, ""),
"forward_to" => Ops.get(fw_rul, 1, ""),
"protocol" => Builtins.tolower(Ops.get(fw_rul, 2, "")),
"req_port" => Builtins.tolower(Ops.get(fw_rul, 3, "")),
# to_port is req_port when undefined
"to_port" => Builtins.tolower(
Ops.get(fw_rul, 4, Ops.get(fw_rul, 3, ""))
),
"req_ip" => Builtins.tolower(Ops.get(fw_rul, 5, ""))
)
end
deep_copy(list_of_rules)
end
# Function removes rule for forwarding into masquerade
# from the list of current rules returned by GetListOfForwardsIntoMasquerade().
#
# @param remove_item [Integer] item number
#
# @see #GetListOfForwardsIntoMasquerade()
def RemoveForwardIntoMasqueradeRule(remove_item)
SetModified()
forward_rules = []
row_counter = 0
Builtins.foreach(
Builtins.splitstring(
Ops.get_string(@SETTINGS, "FW_FORWARD_MASQ", ""),
" "
)
) do |forward_rule|
next if forward_rule == ""
forward_rules = Builtins.add(forward_rules, forward_rule) if row_counter != remove_item
row_counter = Ops.add(row_counter, 1)
end
Ops.set(
@SETTINGS,
"FW_FORWARD_MASQ",
Builtins.mergestring(forward_rules, " ")
)
nil
end
# Adds forward into masquerade rule.
#
# @param [String] source_net
# @param [String] forward_to_ip
# @param [String] protocol
# @param [String] req_port
# @param [String] redirect_to_port
# @param [String] requested_ip
#
# @example
# AddForwardIntoMasqueradeRule ("0/0", "192.168.32.1", "TCP", "80", "8080", "10.0.0.1")
def AddForwardIntoMasqueradeRule(source_net, forward_to_ip, protocol, req_port, redirect_to_port, requested_ip)
SetModified()
masquerade_rules = Ops.get_string(@SETTINGS, "FW_FORWARD_MASQ", "")
masquerade_rules = Ops.add(
Ops.add(
Ops.add(
Ops.add(
Ops.add(
Ops.add(
Ops.add(
Ops.add(masquerade_rules, (masquerade_rules != "") ? " " : ""),
source_net
),
","
),
forward_to_ip
),
","
),
protocol
),
","
),
req_port
)
if redirect_to_port != "" || requested_ip != ""
if requested_ip != ""
masquerade_rules = Ops.add(
Ops.add(
Ops.add(Ops.add(masquerade_rules, ","), redirect_to_port),
","
),
requested_ip
)
# port1 -> port2 are same
elsif redirect_to_port != req_port
masquerade_rules = Ops.add(
Ops.add(masquerade_rules, ","),
redirect_to_port
)
end
end
Ops.set(@SETTINGS, "FW_FORWARD_MASQ", masquerade_rules)
nil
end
# Function returns actual state of logging for rule taken as parameter.
#
# @param [String] rule definition 'ACCEPT' or 'DROP'
# @return [String] 'ALL', 'CRIT', or 'NONE'
#
# @example
# GetLoggingSettings("ACCEPT") -> "CRIT"
# GetLoggingSettings("DROP") -> "CRIT"
def GetLoggingSettings(rule)
ret_val = nil
case rule
when "ACCEPT"
ret_val = if Ops.get_string(@SETTINGS, "FW_LOG_ACCEPT_ALL", "no") == "yes"
"ALL"
elsif Ops.get_string(@SETTINGS, "FW_LOG_ACCEPT_CRIT", "yes") == "yes"
"CRIT"
else
"NONE"
end
when "DROP"
ret_val = if Ops.get_string(@SETTINGS, "FW_LOG_DROP_ALL", "no") == "yes"
"ALL"
elsif Ops.get_string(@SETTINGS, "FW_LOG_DROP_CRIT", "yes") == "yes"
"CRIT"
else
"NONE"
end
else
Builtins.y2error("Possible rules are only 'ACCEPT' or 'DROP'")
end
ret_val
end
# Function sets state of logging for rule taken as parameter.
#
# @param [String] rule definition 'ACCEPT' or 'DROP'
# @param [String] state new logging state 'ALL', 'CRIT', or 'NONE'
#
# @example
# SetLoggingSettings ("ACCEPT", "ALL")
# SetLoggingSettings ("DROP", "NONE")
def SetLoggingSettings(rule, state)
SetModified()
case rule
when "ACCEPT"
case state
when "ALL"
Ops.set(@SETTINGS, "FW_LOG_ACCEPT_CRIT", "yes")
Ops.set(@SETTINGS, "FW_LOG_ACCEPT_ALL", "yes")
when "CRIT"
Ops.set(@SETTINGS, "FW_LOG_ACCEPT_CRIT", "yes")
Ops.set(@SETTINGS, "FW_LOG_ACCEPT_ALL", "no")
else
Ops.set(@SETTINGS, "FW_LOG_ACCEPT_CRIT", "no")
Ops.set(@SETTINGS, "FW_LOG_ACCEPT_ALL", "no")
end
when "DROP"
case state
when "ALL"
Ops.set(@SETTINGS, "FW_LOG_DROP_CRIT", "yes")
Ops.set(@SETTINGS, "FW_LOG_DROP_ALL", "yes")
when "CRIT"
Ops.set(@SETTINGS, "FW_LOG_DROP_CRIT", "yes")
Ops.set(@SETTINGS, "FW_LOG_DROP_ALL", "no")
else
Ops.set(@SETTINGS, "FW_LOG_DROP_CRIT", "no")
Ops.set(@SETTINGS, "FW_LOG_DROP_ALL", "no")
end
else
Builtins.y2error("Possible rules are only 'ACCEPT' or 'DROP'")
end
nil
end
# Function returns yes/no - ignoring broadcast for zone
#
# @param [String] zone
# @return [String] "yes" or "no"
#
# @example
# # Does not log ignored broadcast packets
# GetIgnoreLoggingBroadcast ("EXT") -> "yes"
def GetIgnoreLoggingBroadcast(zone)
if !IsKnownZone(zone)
Builtins.y2error("Unknown zone '%1'", zone)
return nil
end
Ops.get_string(@SETTINGS, Ops.add("FW_IGNORE_FW_BROADCAST_", zone), "no")
end
# Function sets yes/no - ignoring broadcast for zone
#
# @param [String] zone
# @param [String] bcast ignore 'yes' or 'no'
#
# @example
# # Does not log broadcast packets from DMZ
# SetIgnoreLoggingBroadcast ("DMZ", "yes")
def SetIgnoreLoggingBroadcast(zone, bcast)
if !IsKnownZone(zone)
Builtins.y2error("Unknown zone '%1'", zone)
return nil
end
SetModified()
Ops.set(@SETTINGS, Ops.add("FW_IGNORE_FW_BROADCAST_", zone), bcast)
nil
end
# Firewall Expert Rules
# Returns list of rules describing protocols and ports that are allowed
# to be accessed from listed hosts. All is returned as a single string.
# Zone needs to be defined.
#
# @param [String] zone
# @return [String] with rules
def GetAcceptExpertRules(zone)
zone = Builtins.toupper(zone)
# Check for zone
if !Builtins.contains(GetKnownFirewallZones(), zone)
Builtins.y2error("Unknown firewall zone: %1", zone)
return nil
end
Ops.get_string(@SETTINGS, Ops.add("FW_SERVICES_ACCEPT_", zone), "")
end
# Sets expert allow rules for zone.
#
# @param [String] zone
# @param [String] expert_rules whitespace-separated expert_rules
# @return [Boolean] if successful
def SetAcceptExpertRules(zone, expert_rules)
zone = Builtins.toupper(zone)
# Check for zone
if !Builtins.contains(GetKnownFirewallZones(), zone)
Builtins.y2error("Unknown firewall zone: %1", zone)
return false
end
Ops.set(@SETTINGS, Ops.add("FW_SERVICES_ACCEPT_", zone), expert_rules)
SetModified()
true
end
# Returns list of additional kernel modules, that are loaded by firewall on startup.
# For instance "ip_conntrack_ftp" and "ip_nat_ftp" for FTP service.
#
# @return [Array<String>] of kernel modules
#
# @see /etc/sysconfig/SuSEfirewall2 option nr. 32 (FW_LOAD_MODULES)
def GetFirewallKernelModules
k_modules = Builtins.splitstring(
Ops.get_string(@SETTINGS, "FW_LOAD_MODULES", ""),
" \t\n"
)
k_modules = Builtins.filter(k_modules) { |one_module| one_module != "" }
Builtins.toset(k_modules)
end
# Sets list of additional kernel modules to be loaded by firewall on startup.
#
# @param [Array<String>] k_modules list of kernel modules
#
# @see /etc/sysconfig/SuSEfirewall2 option nr. 32
#
# @example
# SuSEFirewall::SetFirewallKernelModules (["ip_conntrack_ftp","ip_nat_ftp"]);
def SetFirewallKernelModules(k_modules)
k_modules = deep_copy(k_modules)
k_modules = Builtins.filter(k_modules) do |one_module|
if one_module.nil?
Builtins.y2error(
"List of modules %1 contains 'nil'! It will be ignored.",
k_modules
)
next false
elsif one_module == ""
Builtins.y2warning(
"List of modules %1 contains an empty string, it will be ignored.",
k_modules
)
next false
end
if Builtins.regexpmatch(one_module, " ") ||
Builtins.regexpmatch(one_module, "\t")
Builtins.y2warning(
"Additional module '%1' contains spaces. They will be evaluated as two or more modules later.",
one_module
)
end
true
end
Ops.set(
@SETTINGS,
"FW_LOAD_MODULES",
Builtins.mergestring(k_modules, " ")
)
SetModified()
nil
end
# Returns translated protocol name. Translation is provided from
# SuSEfirewall2 sysconfig format to l10n format.
#
# @param protocol [String] from sysconfig (e.g., _rpc_)
# @return [String] translated string (e.g., RPC)
def GetProtocolTranslatedName(protocol)
protocol = Builtins.tolower(protocol)
if protocol == ""
""
elsif Ops.get(@protocol_translations, protocol).nil?
Builtins.y2error("Unknown protocol: %1", protocol)
# table item, %1 stands for the buggy protocol name
Builtins.sformat(_("Unknown protocol (%1)"), protocol)
else
Ops.get(@protocol_translations, protocol, "")
end
end
# Returns list of FW_SERVICES_ACCEPT_RELATED_*: Services to allow that are
# considered RELATED by the connection tracking engine, e.g., SLP browsing
# reply or Samba browsing reply.
#
# @param [String] zone
# @return [Array<String>] list of definitions
#
# @example
# GetServicesAcceptRelated ("EXT") -> ["0/0,udp,427", "0/0,udp,137"]
#
# @see #SetServicesAcceptRelated()
def GetServicesAcceptRelated(zone)
if !IsKnownZone(zone)
Builtins.y2error("Uknown zone '%1'", zone)
return []
end
Builtins.splitstring(
Ops.get_string(
@SETTINGS,
Ops.add("FW_SERVICES_ACCEPT_RELATED_", zone),
""
),
" \t\n"
)
end
# Functions sets FW_SERVICES_ACCEPT_RELATED_*: Services to allow that are
# considered RELATED by the connection tracking engine, e.g., SLP browsing
# reply or Samba browsing reply.
#
# @param [String] zone
# @param [Array<String>] ruleset list of rules
#
# @example
# SetServicesAcceptRelated ("EXT", ["0/0,udp,427", "0/0,udp,137"])
#
# @see #GetServicesAcceptRelated()
def SetServicesAcceptRelated(zone, ruleset)
ruleset = deep_copy(ruleset)
if !IsKnownZone(zone)
Builtins.y2error("Uknown zone '%1'", zone)
return
end
ruleset = Builtins.filter(ruleset) { |one_rule| !one_rule.nil? }
SetModified()
Ops.set(
@SETTINGS,
Ops.add("FW_SERVICES_ACCEPT_RELATED_", zone),
Builtins.mergestring(ruleset, "\n")
)
nil
end
def CheckKernelModules
needs_additional_module = false
Builtins.foreach(GetKnownFirewallZones()) do |one_zone|
if Ops.greater_or_equal(
Builtins.size(GetServicesAcceptRelated(one_zone)),
0
)
Builtins.y2milestone("Some ServicesAcceptRelated are defined")
needs_additional_module = true
raise Break
end
end
if needs_additional_module
k_modules = Builtins.splitstring(
Ops.get_string(@SETTINGS, "FW_LOAD_MODULES", ""),
" "
)
if !Builtins.contains(k_modules, @broadcast_related_module)
Builtins.y2warning(
"FW_LOAD_MODULES doesn't contain %1, adding",
@broadcast_related_module
)
k_modules = Builtins.add(k_modules, @broadcast_related_module)
Ops.set(
@SETTINGS,
"FW_LOAD_MODULES",
Builtins.mergestring(k_modules, " ")
)
SetModified()
end
end
nil
end
# Removes old-service definitions before they are added as services defined
# by packages.
def RemoveOldAllowedServiceFromZone(old_service_def, zone)
old_service_def = deep_copy(old_service_def)
Builtins.y2milestone("Removing: %1 from zone %2", old_service_def, zone)
if Ops.get_list(old_service_def, "tcp_ports", []) != []
Builtins.foreach(Ops.get_list(old_service_def, "tcp_ports", [])) do |one_service|
RemoveService(one_service, "TCP", zone)
end
end
if Ops.get_list(old_service_def, "udp_ports", []) != []
Builtins.foreach(Ops.get_list(old_service_def, "udp_ports", [])) do |one_service|
RemoveService(one_service, "UDP", zone)
end
end
if Ops.get_list(old_service_def, "rpc_ports", []) != []
Builtins.foreach(Ops.get_list(old_service_def, "rpc_ports", [])) do |one_service|
RemoveService(one_service, "RPC", zone)
end
end
if Ops.get_list(old_service_def, "ip_protocols", []) != []
Builtins.foreach(Ops.get_list(old_service_def, "ip_protocols", [])) do |one_service|
RemoveService(one_service, "IP", zone)
end
end
if Ops.get_list(old_service_def, "broadcast_ports", []) != []
broadcast = GetBroadcastAllowedPorts()
Ops.set(broadcast, zone, Builtins.filter(Ops.get(broadcast, zone, [])) do |one_port|
!Builtins.contains(
Ops.get_list(old_service_def, "broadcast_ports", []),
one_port
)
end)
SetBroadcastAllowedPorts(broadcast)
end
nil
end
# Converts old built-in service definitions to services defined by packages.
#
# @see #bnc 399217
def ConvertToServicesDefinedByPackages
return if @already_converted
if FileUtils.Exists(@converted_to_services_dbp_file)
@already_converted = true
return
end
# $[ zone : $[ protocol : [ list of ports ] ] ]
current_conf = {}
Builtins.foreach(GetKnownFirewallZones()) do |zone|
Ops.set(current_conf, zone, {})
Builtins.foreach(@supported_protocols) do |protocol|
Ops.set(
current_conf,
[zone, protocol],
GetAllowedServicesForZoneProto(zone, protocol)
)
Ops.set(
current_conf,
[zone, "broadcast"],
Builtins.splitstring(GetBroadcastConfiguration(zone), " \n")
)
end
end
Builtins.y2milestone("Current conf: %1", current_conf)
Yast.import "SuSEFirewallServices" # lazy import due to circular dependencies
Builtins.foreach(GetKnownFirewallZones()) do |zone|
Builtins.foreach(SuSEFirewallServices.OLD_SERVICES) do |old_service_id, old_service_def|
Builtins.y2milestone("Checking %1 in %2 zone", old_service_id, zone)
if Ops.get_list(old_service_def, "tcp_ports", []) != [] &&
ArePortsOrServicesAllowed(
Ops.get_list(old_service_def, "tcp_ports", []),
"TCP",
zone,
true
) != true
next
end
if Ops.get_list(old_service_def, "udp_ports", []) != [] &&
ArePortsOrServicesAllowed(
Ops.get_list(old_service_def, "udp_ports", []),
"UDP",
zone,
true
) != true
next
end
if Ops.get_list(old_service_def, "rpc_ports", []) != [] &&
ArePortsOrServicesAllowed(
Ops.get_list(old_service_def, "rpc_ports", []),
"RPC",
zone,
false
) != true
next
end
if Ops.get_list(old_service_def, "ip_protocols", []) != [] &&
ArePortsOrServicesAllowed(
Ops.get_list(old_service_def, "ip_protocols", []),
"IP",
zone,
false
) != true
next
end
if Ops.get_list(old_service_def, "broadcast_ports", []) != [] &&
IsBroadcastAllowed(
Ops.get_list(old_service_def, "broadcast_ports", []),
zone
) != true
next
end
if Ops.get_list(old_service_def, "convert_to", []) == []
Builtins.y2milestone(
"Service %1 supported, but it doesn't have any replacement",
old_service_id
)
next
end
replaced = false
Builtins.foreach(Ops.get_list(old_service_def, "convert_to", [])) do |replacement|
if SuSEFirewallServices.IsKnownService(replacement)
Builtins.y2milestone(
"Old service %1 matches %2",
old_service_id,
replacement
)
RemoveOldAllowedServiceFromZone(old_service_def, zone)
SetServicesForZones([replacement], [zone], true)
replaced = true
raise Break
end
end
if !replaced
Builtins.y2warning(
"Old service %1 matches %2 but none are installed",
old_service_id,
Ops.get_list(old_service_def, "convert_to", [])
)
end
end
end
Builtins.y2milestone("Converting done")
@already_converted = true
nil
end
# Local function allows ports for requested protocol and zone.
#
# @param [Array<string>] add_ports ports to be added
# @param [String] protocol
# @param [String] zone
def AddAllowedPortsOrServices(add_ports, protocol, zone)
add_ports = deep_copy(add_ports)
if Ops.less_than(Builtins.size(add_ports), 1)
Builtins.y2warning(
"Undefined list of %1 services/ports for service",
protocol
)
return
end
SetModified()
# all allowed ports
allowed_services = GetAllowedServicesForZoneProto(zone, protocol)
allowed_services = Convert.convert(
Builtins.union(allowed_services, add_ports),
from: "list",
to: "list <string>"
)
allowed_services = PortRanges.FlattenServices(allowed_services, protocol)
SetAllowedServicesForZoneProto(allowed_services, zone, protocol)
nil
end
# Sets whether ports need to be open already during boot
# bsc#916376
#
# @param [Boolean] new_state
# @return [Boolean] current state
def full_init_on_boot(new_state)
@SETTINGS["FW_BOOT_FULL_INIT"] = new_state ? "yes" : "no"
SetModified()
@SETTINGS["FW_BOOT_FULL_INIT"] == "yes"
end
publish variable: :FIREWALL_PACKAGE, type: "const string"
publish variable: :configuration_has_been_read, type: "boolean", private: true
publish variable: :special_all_interface_string, type: "string"
publish variable: :max_port_number, type: "integer"
publish variable: :special_all_interface_zone, type: "string"
publish variable: :SETTINGS, type: "map <string, any>", private: true
publish variable: :modified, type: "boolean", private: true
publish variable: :is_running, type: "boolean", private: true
publish variable: :DEFAULT_SETTINGS, type: "map <string, string>", private: true
publish variable: :verbose_level, type: "integer", private: true
publish variable: :known_firewall_zones, type: "list <string>", private: true
publish variable: :zone_names, type: "map <string, string>", private: true
publish variable: :int_zone_shortname, type: "string", private: true
publish variable: :supported_protocols, type: "list <string>", private: true
publish variable: :service_defined_by, type: "list <string>", private: true
publish variable: :allowed_conflict_services, type: "map <string, list <string>>", private: true
publish variable: :firewall_service, type: "string", private: true
publish variable: :SuSEFirewall_variables, type: "list <string>", private: true
publish variable: :broadcast_related_module, type: "string", private: true
publish function: :SetModified, type: "void ()"
publish function: :ResetModified, type: "void ()"
publish function: :GetKnownFirewallZones, type: "list <string> ()"
publish function: :IsServiceSupportedInZone, type: "boolean (string, string)"
publish function: :GetSpecialInterfacesInZone, type: "list <string> (string)"
publish function: :AddSpecialInterfaceIntoZone, type: "void (string, string)"
publish variable: :report_only_once, type: "list <string>", private: true
publish function: :ReportOnlyOnce, type: "boolean (string)", private: true
publish function: :IsAnyNetworkInterfaceSupported, type: "boolean ()"
publish function: :GetListOfSuSEFirewallVariables, type: "list <string> ()", private: true
publish function: :IncreaseVerbosity, type: "void ()", private: true
publish function: :DecreaseVerbosity, type: "void ()", private: true
publish function: :IsVerbose, type: "boolean ()", private: true
publish function: :GetDefaultValue, type: "string (string)", private: true
publish function: :ReadSysconfigSuSEFirewall, type: "void (list <string>)", private: true
publish function: :ResetSysconfigSuSEFirewall, type: "void (list <string>)", private: true
publish function: :WriteSysconfigSuSEFirewall, type: "boolean (list <string>)", private: true
publish function: :IsSupportedProtocol, type: "boolean (string)", private: true
publish function: :IsKnownZone, type: "boolean (string)", private: true
publish function: :GetZoneConfigurationString, type: "string (string)", private: true
publish function: :GetConfigurationStringZone, type: "string (string)", private: true
publish function: :GetAllowedServicesForZoneProto, type: "list <string> (string, string)", private: true
publish function: :SetAllowedServicesForZoneProto, type: "void (list <string>, string, string)", private: true
publish function: :GetBroadcastConfiguration, type: "string (string)", private: true
publish function: :SetBroadcastConfiguration, type: "void (string, string)", private: true
publish function: :GetBroadcastAllowedPorts, type: "map <string, list <string>> ()"
publish function: :SetBroadcastAllowedPorts, type: "void (map <string, list <string>>)"
publish function: :IsBroadcastAllowed, type: "boolean (list <string>, string)", private: true
publish function: :RemoveAllowedBroadcast, type: "void (list <string>, string)", private: true
publish function: :AddAllowedBroadcast, type: "void (list <string>, string)", private: true
publish function: :RemoveServiceFromProtocolZone, type: "boolean (string, string, string)", private: true
publish function: :RemoveAllowedPortsOrServices, type: "void (list <string>, string, string, boolean)", private: true
publish function: :AddAllowedPortsOrServices, type: "void (list <string>, string, string)", private: true
publish function: :RemoveServiceDefinedByPackageFromZone, type: "void (string, string)", private: true
publish function: :AddServiceDefinedByPackageIntoZone, type: "void (string, string)", private: true
publish function: :RemoveServiceSupportFromZone, type: "void (string, string)", private: true
publish function: :AddServiceSupportIntoZone, type: "void (string, string)", private: true
publish variable: :check_and_install_package, type: "boolean", private: true
publish function: :SetInstallPackagesIfMissing, type: "void (boolean)"
publish function: :SuSEFirewallIsInstalled, type: "boolean ()"
publish variable: :fw_service_can_be_configured, type: "boolean", private: true
publish function: :GetModified, type: "boolean ()"
publish function: :ResetReadFlag, type: "void ()"
publish function: :GetZoneFullName, type: "string (string)"
publish function: :SetProtectFromInternalZone, type: "void (boolean)"
publish function: :GetProtectFromInternalZone, type: "boolean ()"
publish function: :SetSupportRoute, type: "void (boolean)"
publish function: :GetSupportRoute, type: "boolean ()"
publish function: :SetTrustIPsecAs, type: "void (string)"
publish function: :GetTrustIPsecAs, type: "string ()"
publish function: :GetStartService, type: "boolean ()"
publish function: :SetStartService, type: "void (boolean)"
publish function: :GetEnableService, type: "boolean ()"
publish function: :SetEnableService, type: "void (boolean)"
publish function: :StartServices, type: "boolean ()"
publish function: :StopServices, type: "boolean ()"
publish function: :EnableServices, type: "boolean ()"
publish function: :DisableServices, type: "boolean ()"
publish function: :IsEnabled, type: "boolean ()"
publish function: :IsStarted, type: "boolean ()"
publish function: :Export, type: "map <string, any> ()"
publish function: :Import, type: "void (map <string, any>)"
publish function: :read_and_import, type: "void (map <string, any>)"
publish function: :IsInterfaceInZone, type: "boolean (string, string)"
publish function: :GetZoneOfInterface, type: "string (string)"
publish function: :GetZonesOfInterfaces, type: "list <string> (list <string>)"
publish function: :GetInterfacesInZoneSupportingAnyFeature, type: "list <string> (string)"
publish function: :GetZonesOfInterfacesWithAnyFeatureSupported, type: "list <string> (list <string>)"
publish function: :GetAllKnownInterfaces, type: "list <map <string, string>> ()"
publish function: :GetAllNonDialUpInterfaces, type: "list <string> ()"
publish function: :GetAllDialUpInterfaces, type: "list <string> ()"
publish function: :GetListOfKnownInterfaces, type: "list <string> ()"
publish function: :RemoveInterfaceFromZone, type: "void (string, string)"
publish function: :AddInterfaceIntoZone, type: "void (string, string)"
publish function: :GetInterfacesInZone, type: "list <string> (string)"
publish function: :GetFirewallInterfaces, type: "list <string> ()"
publish function: :InterfacesSupportedByAnyFeature, type: "list <string> (string)"
publish function: :ArePortsOrServicesAllowed, type: "boolean (list <string>, string, string, boolean)", private: true
publish function: :HaveService, type: "boolean (string, string, string)"
publish function: :AddService, type: "boolean (string, string, string)"
publish function: :RemoveService, type: "boolean (string, string, string)"
publish function: :IsServiceDefinedByPackageSupportedInZone, type: "boolean (string, string)", private: true
publish function: :GetServicesInZones, type: "map <string, map <string, boolean>> (list <string>)"
publish function: :GetServices, type: "map <string, map <string, boolean>> (list <string>)"
publish function: :SetServicesForZones, type: "boolean (list <string>, list <string>, boolean)"
publish function: :SetServices, type: "boolean (list <string>, list <string>, boolean)"
publish function: :ReadDefaultConfiguration, type: "void ()", private: true
publish function: :ReadCurrentConfiguration, type: "void ()", private: true
publish variable: :converted_to_services_dbp_file, type: "string", private: true
publish variable: :already_converted, type: "boolean", private: true
publish function: :ConvertToServicesDefinedByPackages, type: "void ()"
publish function: :FillUpEmptyConfig, type: "void ()", private: true
publish function: :Read, type: "boolean ()"
publish function: :AnyRPCServiceInConfiguration, type: "boolean ()", private: true
publish function: :ActivateConfiguration, type: "boolean ()"
publish function: :WriteConfiguration, type: "boolean ()"
publish function: :CheckKernelModules, type: "void ()", private: true
publish function: :WriteOnly, type: "boolean ()"
publish function: :Write, type: "boolean ()"
publish function: :SaveAndRestartService, type: "boolean ()"
publish function: :GetAdditionalServices, type: "list <string> (string, string)"
publish function: :SetAdditionalServices, type: "void (string, string, list <string>)"
publish function: :IsOtherFirewallRunning, type: "boolean ()"
publish function: :GetFirewallInterfacesMap, type: "map <string, list <string>> ()"
publish function: :RemoveSpecialInterfaceFromZone, type: "void (string, string)"
publish function: :GetMasquerade, type: "boolean ()"
publish function: :SetMasquerade, type: "void (boolean)"
publish function: :GetListOfForwardsIntoMasquerade, type: "list <map <string, string>> ()"
publish function: :RemoveForwardIntoMasqueradeRule, type: "void (integer)"
publish function: :AddForwardIntoMasqueradeRule, type: "void (string, string, string, string, string, string)"
publish function: :GetLoggingSettings, type: "string (string)"
publish function: :SetLoggingSettings, type: "void (string, string)"
publish function: :GetIgnoreLoggingBroadcast, type: "string (string)"
publish function: :SetIgnoreLoggingBroadcast, type: "void (string, string)"
publish function: :AddXenSupport, type: "void ()"
publish function: :GetAcceptExpertRules, type: "string (string)"
publish function: :SetAcceptExpertRules, type: "boolean (string, string)"
publish function: :GetFirewallKernelModules, type: "list <string> ()"
publish function: :SetFirewallKernelModules, type: "void (list <string>)"
publish variable: :protocol_translations, type: "map <string, string>", private: true
publish function: :GetProtocolTranslatedName, type: "string (string)"
publish function: :GetServicesAcceptRelated, type: "list <string> (string)"
publish function: :SetServicesAcceptRelated, type: "void (string, list <string>)"
publish function: :RemoveOldAllowedServiceFromZone, type: "void (map <string, any>, string)", private: true
publish variable: :needed_packages_installed, type: "boolean"
publish function: :full_init_on_boot, type: "boolean (boolean)"
end
end