commit 6b9867cd5c5e2c83adeec42666521a420e59ef11 Author: Thomas Woerner Date: Fri Sep 26 17:11:11 2014 +0200 New runtimeToPermanent and tracked passsthrough support - New D-Bus method DBUS_INTERFACE.runtimeToPermanent Copyies all needed files from the runtime into the permanent environmant - New RT_TO_PERM_FAILED error used in case of runtime to permanent failure - New D-Bus method DBUS_INTERFACE.runtimeToPermanent - New firewall-cmd option --runtime-to-permanent - Enabled support for tracked runtime passthrough versus untracked simple passthrough (runtime --passthrough option): This is needed to have tracked passthrough settings after a runtime to permanent call. - New D-Bus methods for tracked passthrough in DBUS_INTERFACE_DIRECT: addPassthrough, removePassthrough, queryPassthrough, getAllPassthroughs, setAllPassthroughs, removeAllPassthroughs, - New D-Bus signals for tracked passthrough in DBUS_INTERFACE_DIRECT: PassthroughAdded, PassthroughRemoved - Support for new D-Bus methods and signals in client.py - Enabled runtime options in firewall-cmd for --get-[all-]passthroughs --{add|remove|query}-passthrough - Enabled tracked runtime passthrough settings in firewall-config - Using list types for rule args in fw_direct to enable runtime-to-permanent data usage - Fixed or added string conversions for direct rules and passthrough, also for lockdown_whitelist commands, contexts and users - Fixed bash_completion script - firewall-cmd man page: Added unracked comment for runtime --passthrough - firewalld.dbus man page: Added new D-Bus methods and signals commit 735fa38bd9e49945656dd8b44ee60bb962196b6d Author: Thomas Woerner Date: Mon Sep 29 15:57:59 2014 +0200 Fixed runtimeToPermanent to use DBUS_INTERFACE.get{Service,IcmpType,Zone}Set tings() The use of DBUS_INTERFACE.getZoneSettings() is needed to be able to pass the identical check in the runtimeToPermanent call. diff -up firewalld-0.3.9/doc/xml/firewall-cmd.xml.RHBZ#993650 firewalld-0.3.9/doc/xml/firewall-cmd.xml --- firewalld-0.3.9/doc/xml/firewall-cmd.xml.RHBZ#993650 2014-09-29 22:40:23.976109890 +0200 +++ firewalld-0.3.9/doc/xml/firewall-cmd.xml 2014-09-29 22:41:16.188349186 +0200 @@ -915,21 +915,21 @@ - + { ipv4 | ipv6 | eb } args - Pass a command through to the firewall. args can be all iptables, ip6tables and ebtables command line arguments. + Pass a command through to the firewall. args can be all iptables, ip6tables and ebtables command line arguments. This command is untracked, which means that firewalld is not able to provide information about this command later on, also not a listing of the untracked passthoughs. - + - + Get all permanent passthrough as a newline separated list of the ipv value and arguments. @@ -938,7 +938,7 @@ - { ipv4 | ipv6 | eb } + { ipv4 | ipv6 | eb } Get all permanent passthrough rules for the ipv value as a newline separated list of the priority and arguments. @@ -947,7 +947,7 @@ - { ipv4 | ipv6 | eb } args + { ipv4 | ipv6 | eb } args Add a permanent passthrough rule with the arguments args for the ipv value. @@ -956,7 +956,7 @@ - { ipv4 | ipv6 | eb } args + { ipv4 | ipv6 | eb } args Remove a permanent passthrough rule with the arguments args for the ipv value. @@ -965,7 +965,7 @@ - { ipv4 | ipv6 | eb } args + { ipv4 | ipv6 | eb } args Return whether a permanent passthrough rule with the arguments args exists for the ipv value. Returns 0 if true, 1 otherwise. diff -up firewalld-0.3.9/doc/xml/firewalld.dbus.xml.RHBZ#993650 firewalld-0.3.9/doc/xml/firewalld.dbus.xml --- firewalld-0.3.9/doc/xml/firewalld.dbus.xml.RHBZ#993650 2014-09-29 22:40:23.972109870 +0200 +++ firewalld-0.3.9/doc/xml/firewalld.dbus.xml 2014-09-29 22:46:02.838503889 +0200 @@ -292,6 +292,17 @@ + + runtimeToPermanent() → Nothing + + + Make runtime settings permanent. Replaces permanent settings with runtime settings for zones, services, icmptypes, direct and policies (lockdown whitelist). + + + Possible errors: RT_TO_PERM_FAILED + + + @@ -313,6 +324,17 @@ + + addPassthrough(s: ipv, as: args) → Nothing + + + Add a tracked passthrough rule with the arguments args for ipv being either ipv4 (iptables) or ipv6 (ip6tables) or eb (ebtables). + + + Possible errors: INVALID_IPV, ALREADY_ENABLED, COMMAND_FAILED + + + addRule(s: ipv, s: table, s: chain, i: priority, as: args) → Nothing @@ -329,6 +351,22 @@ + + getAllPassthroughs() → a(sas) + + + Get all tracked passthrough rules added in all ipv types in format: ipv, rule. + This concerns only rules previously added with addPassthrough. + Return value is a array of (ipv, array of arguments). + + + + ipv (s): either ipv4 (iptables) or ipv6 (ip6tables) or eb (ebtables). + arguments (as): array of commands, parameters and other iptables/ip6tables/ebtables command line options. + + + + getAllRules() → a(sssias) @@ -358,6 +396,7 @@ Pass a command through to the firewall. ipv can be either ipv4 or ipv6 or eb. args can be all iptables, ip6tables and ebtables command line arguments. + This command is untracked, which means that firewalld is not able to provide information about this command later on. @@ -369,6 +408,18 @@ + + queryPassthrough(s: ipv, as: args) → b + + + Return whether a tracked passthrough rule with the arguments args exists for ipv being either ipv4 (iptables) or ipv6 (ip6tables) or eb (ebtables). + This concerns only rules previously added with addPassthrough. + + + Possible errors: INVALID_IPV + + + queryRule(s: ipv, s: table, s: chain, i: priority, as: args) → b @@ -385,6 +436,18 @@ + + removePassthrough(s: ipv, as: args) → Nothing + + + Remove a tracked passthrough rule with arguments args for ipv being either ipv4 (iptables) or ipv6 (ip6tables) or eb (ebtables). + Only rules previously added with addPassthrough can be removed this way. + + + Possible errors: INVALID_IPV, NOT_ENABLED, COMMAND_FAILED + + + removeRule(s: ipv, s: table, s: chain, i: priority, as: args) → Nothing @@ -423,6 +486,22 @@ + + PassthroughAdded(s: ipv, as: args) + + + Emitted when a tracked passthruogh rule with args has been added for ipv being either ipv4 (iptables) or ipv6 (ip6tables) or eb (ebtables). + + + + + PassthroughRemoved(s: ipv, as: args) + + + Emitted when a tracked passthrough rule with args has been removed for ipv being either ipv4 (iptables) or ipv6 (ip6tables) or eb (ebtables). + + + RuleAdded(s: ipv, s: table, s: chain, i: priority, as: args) diff -up firewalld-0.3.9/shell-completion/bash/firewall-cmd.RHBZ#993650 firewalld-0.3.9/shell-completion/bash/firewall-cmd --- firewalld-0.3.9/shell-completion/bash/firewall-cmd.RHBZ#993650 2013-12-03 14:59:48.000000000 +0100 +++ firewalld-0.3.9/shell-completion/bash/firewall-cmd 2014-09-29 22:41:16.191349178 +0200 @@ -60,10 +60,9 @@ OPTIONS_PERMANENT="${OPTIONS_CONFIG} --z OPTIONS_DIRECT="--passthrough \ --add-chain --remove-chain --query-chain --get-chains --get-all-chains \ - --add-rule --remove-rule --query-rule --get-rules --get-all-rules" - -OPTIONS_DIRECT_PERMANENT="--add-passthrough --remove-passthrough \ - --query-passthrough --get-passthroughs --get-all-passthroughs" + --add-rule --remove-rule --query-rule --get-rules --get-all-rules \ + --add-passthrough --remove-passthrough \ + --query-passthrough --get-passthroughs --get-all-passthroughs" # these all can be used as a "first" option OPTIONS_GENERAL="--help --version \ @@ -108,11 +107,11 @@ _firewall_cmd() _available_interfaces ;; --permanent) - [[ ${words[@]} == *--direct* ]] && opts="${OPTIONS_DIRECT} ${OPTIONS_DIRECT_PERMANENT}" || opts="${OPTIONS_PERMANENT} --direct" + [[ ${words[@]} == *--direct* ]] && opts="${OPTIONS_DIRECT}" || opts="${OPTIONS_PERMANENT} --direct" COMPREPLY=( $( compgen -W "${opts}" -- "$cur" ) ) ;; --direct) - [[ ${words[@]} == *--permanent* ]] && opts="${OPTIONS_DIRECT} ${OPTIONS_DIRECT_PERMANENT}" || opts="${OPTIONS_DIRECT} --permanent" + [[ ${words[@]} == *--permanent* ]] && opts="${OPTIONS_DIRECT}" || opts="${OPTIONS_DIRECT} --permanent" COMPREPLY=( $( compgen -W "${opts}" -- "$cur" ) ) ;; --passthrough|--*-chain|--get-chains|--*-rule|--get-rules) diff -up firewalld-0.3.9/src/firewall/client.py.RHBZ#993650 firewalld-0.3.9/src/firewall/client.py --- firewalld-0.3.9/src/firewall/client.py.RHBZ#993650 2014-09-29 22:40:23.973109875 +0200 +++ firewalld-0.3.9/src/firewall/client.py 2014-09-29 22:41:16.196349207 +0200 @@ -764,13 +764,16 @@ class FirewallClientDirect(object): def getAllPassthroughs(self): return self.settings[2] @handle_exceptions + def setAllPassthroughs(self, passthroughs): + self.settings[2] = passthroughs + @handle_exceptions + def removeAllPassthroughs(self): + self.settings[2] = passthroughs + @handle_exceptions def getPassthroughs(self, ipv): return [ entry[1] for entry in self.settings[2] \ if entry[0] == ipv ] @handle_exceptions - def setAllPassthroughs(self, passthroughs): - self.settings[2] = passthroughs - @handle_exceptions def addPassthrough(self, ipv, args): idx = (ipv, args) if idx not in self.settings[2]: @@ -1005,6 +1008,8 @@ class FirewallClient(object): "direct:chain-removed": "ChainRemoved", "direct:rule-added": "RuleAdded", "direct:rule-removed": "RuleRemoved", + "direct:passthrough-added": "PassthroughAdded", + "direct:passthrough-removed": "PassthroughRemoved", "config:direct:updated": "config:direct:Updated", # policy callbacks "lockdown-enabled": "LockdownEnabled", @@ -1195,6 +1200,11 @@ class FirewallClient(object): @slip.dbus.polkit.enable_proxy @handle_exceptions + def runtimeToPermanent(self): + self.fw.runtimeToPermanent() + + @slip.dbus.polkit.enable_proxy + @handle_exceptions def get_property(self, prop): return dbus_to_python(self.fw_properties.Get(DBUS_INTERFACE, prop)) @@ -1566,6 +1576,38 @@ class FirewallClient(object): def passthrough(self, ipv, args): return dbus_to_python(self.fw_direct.passthrough(ipv, args)) + # tracked passthrough + + @slip.dbus.polkit.enable_proxy + @handle_exceptions + def getAllPassthroughs(self): + return dbus_to_python(self.fw_direct.getAllPassthroughs()) + + @slip.dbus.polkit.enable_proxy + @handle_exceptions + def removeAllPassthroughs(self): + self.fw_direct.removeAllPassthroughs() + + @slip.dbus.polkit.enable_proxy + @handle_exceptions + def getPassthroughs(self, ipv): + return dbus_to_python(self.fw_direct.getPassthroughs(ipv)) + + @slip.dbus.polkit.enable_proxy + @handle_exceptions + def addPassthrough(self, ipv, args): + self.fw_direct.addPassthrough(ipv, args) + + @slip.dbus.polkit.enable_proxy + @handle_exceptions + def removePassthrough(self, ipv, args): + self.fw_direct.removePassthrough(ipv, args) + + @slip.dbus.polkit.enable_proxy + @handle_exceptions + def queryPassthrough(self, ipv, args): + return dbus_to_python(self.fw_direct.queryPassthrough(ipv, args)) + # lockdown @slip.dbus.polkit.enable_proxy diff -up firewalld-0.3.9/src/firewall-cmd.RHBZ#993650 firewalld-0.3.9/src/firewall-cmd --- firewalld-0.3.9/src/firewall-cmd.RHBZ#993650 2014-09-29 22:40:24.039110186 +0200 +++ firewalld-0.3.9/src/firewall-cmd 2014-09-29 22:49:38.406206387 +0200 @@ -68,6 +68,8 @@ Status Options --state Return and print firewalld state --reload Reload firewall and keep state information --complete-reload Reload firewall and loose state information + --runtime-to-permanent + Create permanent from runtime configuration Permanent Options --permanent Set an option permanently @@ -204,18 +206,18 @@ Direct Options Return whether a rule with priority has been added to chain in table [P] --passthrough {ipv4|ipv6|eb} ... - Pass a command through + Pass a command through (untracked by firewalld) --get-all-passthroughs - Get all passthrough rules [P only] + Get all tracked passthrough rules [P] --get-passthroughs {ipv4|ipv6|eb} ... - Get passthrough rules [P only] + Get tracked passthrough rules [P] --add-passthrough {ipv4|ipv6|eb} ... - Add a new passthrough rule [P only] + Add a new tracked passthrough rule [P] --remove-passthrough {ipv4|ipv6|eb} ... - Remove a passthrough rule [P only] + Remove a tracked passthrough rule [P] --query-passthrough {ipv4|ipv6|eb} ... - Return whether the passthrough rule has been added - [P only] + Return whether the tracked passthrough rule has been + added [P] Lockdown Options --lockdown-on Enable lockdown. @@ -373,6 +375,8 @@ parser_group_standalone.add_argument("-V parser_group_standalone.add_argument("--state", action="store_true") parser_group_standalone.add_argument("--reload", action="store_true") parser_group_standalone.add_argument("--complete-reload", action="store_true") +parser_group_standalone.add_argument("--runtime-to-permanent", + action="store_true") parser_group_standalone.add_argument("--panic-on", action="store_true") parser_group_standalone.add_argument("--panic-off", action="store_true") parser_group_standalone.add_argument("--query-panic", action="store_true") @@ -524,7 +528,7 @@ a = parser.parse_args(args) options_standalone = a.help or a.version or \ - a.state or a.reload or a.complete_reload or \ + a.state or a.reload or a.complete_reload or a.runtime_to_permanent or \ a.panic_on or a.panic_off or a.query_panic or \ a.lockdown_on or a.lockdown_off or a.query_lockdown or \ a.get_default_zone or a.set_default_zone or \ @@ -582,9 +586,7 @@ options_direct = a.passthrough or \ a.add_chain or a.remove_chain or a.query_chain or \ a.get_chains or a.get_all_chains or \ a.add_rule or a.remove_rule or a.remove_rules or a.query_rule or \ - a.get_rules or a.get_all_rules - -options_direct_permanent = \ + a.get_rules or a.get_all_rules or \ a.add_passthrough or a.remove_passthrough or a.query_passthrough or \ a.get_passthroughs or a.get_all_passthroughs @@ -601,30 +603,24 @@ options_list_get = a.help or a.version o # Check various impossible combinations of options if not (options_standalone or options_zone or \ - options_permanent or options_direct or options_direct_permanent or \ + options_permanent or options_direct or \ options_permanent_only): __fail(parser.format_usage() + "No option specified.") if options_standalone and (options_zone or options_permanent or \ - options_direct or options_direct_permanent or \ - options_permanent_only): + options_direct or options_permanent_only): __fail(parser.format_usage() + "Can't use stand-alone options with other options.") -if (options_direct or options_direct_permanent or options_permanent_only) and \ - (options_zone): +if (options_direct or options_permanent_only) and (options_zone): __fail(parser.format_usage() + "Can't use 'direct' options with other options.") -if (a.direct and not (options_direct or options_direct_permanent)) or \ - ((options_direct or options_direct_permanent) and not a.direct): +if (a.direct and not options_direct) or \ + (options_direct and not a.direct): __fail(parser.format_usage() + "Wrong usage of 'direct' options.") -if options_direct_permanent and not a.permanent: - __fail(parser.format_usage() + - "Option can be used only with --permanent.") - if options_permanent_only and not a.permanent: __fail(parser.format_usage() + "Option can be used only with --permanent.") @@ -774,7 +770,7 @@ if a.permanent: # apply whitelist changes fw.config().policies().setLockdownWhitelist(whitelist) - elif options_direct or options_direct_permanent: + elif options_direct: settings = fw.config().direct().getSettings() if a.passthrough: @@ -1053,6 +1049,8 @@ elif a.reload: fw.reload() elif a.complete_reload: fw.complete_reload() +elif a.runtime_to_permanent: + fw.runtimeToPermanent() elif a.direct: if a.passthrough: if len (a.passthrough) < 2: @@ -1060,6 +1058,32 @@ elif a.direct: msg = fw.passthrough(_check_ipv(a.passthrough[0]), splitArgs(a.passthrough[1])) if msg: print(msg) + + elif a.add_passthrough: + if len (a.add_passthrough) < 2: + __fail("usage: --direct --add-passthrough { ipv4 | ipv6 | eb } ") + fw.addPassthrough(_check_ipv(a.add_passthrough[0]), + splitArgs(a.add_passthrough[1])) + elif a.remove_passthrough: + if len (a.remove_passthrough) < 2: + __fail("usage: --direct --remove-passthrough { ipv4 | ipv6 | eb } ") + fw.removePassthrough(_check_ipv(a.remove_passthrough[0]), + splitArgs(a.remove_passthrough[1])) + elif a.query_passthrough: + if len (a.query_passthrough) < 2: + __fail("usage: --direct --query-passthrough { ipv4 | ipv6 | eb } ") + __print_query_result( + fw.queryPassthrough(_check_ipv(a.query_passthrough[0]), + splitArgs(a.query_passthrough[1]))) + elif a.get_passthroughs: + rules = fw.getPassthroughs(_check_ipv(a.get_passthroughs[0])) + for rule in rules: + __print(joinArgs(rule)) + sys.exit(0) + elif a.get_all_passthroughs: + for (ipv,rule) in fw.getAllPassthroughs(): + __print("%s %s" % (ipv, joinArgs(rule))) + sys.exit(0) elif a.add_chain: fw.addChain(_check_ipv(a.add_chain[0]), a.add_chain[1], a.add_chain[2]) elif a.remove_chain: diff -up firewalld-0.3.9/src/firewall-config.glade.RHBZ#993650 firewalld-0.3.9/src/firewall-config.glade --- firewalld-0.3.9/src/firewall-config.glade.RHBZ#993650 2014-09-29 22:40:23.986109937 +0200 +++ firewalld-0.3.9/src/firewall-config.glade 2014-09-29 22:41:16.195349202 +0200 @@ -2115,6 +2115,22 @@ True + + + True + False + + + + + True + False + Make runtime configuration permanent + Runtime To permant + True + + + @@ -3928,7 +3944,7 @@ False 0.49000000953674316 gtk-network - 1 + 1 False @@ -3988,7 +4004,7 @@ True False gtk-network - 1 + 1 False @@ -4718,21 +4734,6 @@ - - True - False - 0 - 0 - Passthrough rules can only be modified for the permanent configuration. - True - - - False - False - 2 - - - True False @@ -4744,7 +4745,7 @@ False False - 3 + 2 @@ -4780,7 +4781,7 @@ True True - 4 + 3 @@ -4849,7 +4850,7 @@ False True - 5 + 4 @@ -6690,7 +6691,7 @@ True False gtk-network - 1 + 1 False @@ -7322,7 +7323,7 @@ True False gtk-properties - 1 + 1 False diff -up firewalld-0.3.9/src/firewall-config.RHBZ#993650 firewalld-0.3.9/src/firewall-config --- firewalld-0.3.9/src/firewall-config.RHBZ#993650 2014-09-29 22:40:24.043110205 +0200 +++ firewalld-0.3.9/src/firewall-config 2014-09-29 22:41:16.193349185 +0200 @@ -912,6 +912,8 @@ class FirewallConfig(object): self.fw.connect("direct:chain-removed", self.direct_chain_removed_cb) self.fw.connect("direct:rule-added", self.direct_rule_added_cb) self.fw.connect("direct:rule-removed", self.direct_rule_removed_cb) + self.fw.connect("direct:passthrough-added", self.direct_passthrough_added_cb) + self.fw.connect("direct:passthrough-removed", self.direct_passthrough_removed_cb) self.fw.connect("config:direct:updated", self.direct_updated_cb) self.fw.connect("config:zone-added", self.conf_zone_added_cb) @@ -1737,7 +1739,6 @@ class FirewallConfig(object): self.serviceConfPortBox.show() self.serviceConfModuleBox.show() self.icmpDialogIcmpEditBox.show() - self.directPassthroughBox.set_sensitive(not self.runtime_view) self.load_zones() self.load_services() @@ -1891,6 +1892,9 @@ class FirewallConfig(object): self.default_zone = new_default_zone self.changes_applied() + def onRuntimeToPermanent(self, *args): + self.fw.runtimeToPermanent() + def on_defaultZoneViewSelection_changed(self, selection): (model, iter) = selection.get_selected() if not iter: @@ -4266,7 +4270,7 @@ class FirewallConfig(object): if self.runtime_view: chains = self.fw.getAllChains() rules = self.fw.getAllRules() - passthroughs = [ ] + passthroughs = self.fw.getAllPassthroughs() else: direct = self.fw.config().direct() settings = direct.getSettings() @@ -5085,6 +5089,34 @@ class FirewallConfig(object): self.fw.config().direct().update(settings) self.changes_applied() + def direct_passthrough_added_cb(self, ipv, args): + print "direct_passthrough_added_cb", repr(ipv), repr(args) + if not self.show_direct: + return + joined_args = joinArgs(args) + print "joined_args=%s" % repr(joined_args) + iter = self.directPassthroughStore.get_iter_first() + while iter: + if self.directPassthroughStore.get_value(iter, 0) == ipv and \ + self.directPassthroughStore.get_value(iter, 1) == joined_args: + return + iter = self.directPassthroughStore.iter_next(iter) + self.directPassthroughStore.append([ipv, joined_args]) + + def direct_passthrough_removed_cb(self, ipv, args): + print "direct_passthrough_removed_cb", repr(ipv), repr(args) + if not self.show_direct: + return + joined_args = joinArgs(args) + print "joined_args=%s" % repr(joined_args) + iter = self.directPassthroughStore.get_iter_first() + while iter: + if self.directPassthroughStore.get_value(iter, 0) == ipv and \ + self.directPassthroughStore.get_value(iter, 1) == joined_args: + self.directPassthroughStore.remove(iter) + break + iter = self.directPassthroughStore.iter_next(iter) + def add_edit_direct_passthrough(self, add): if add: old_ipv = "" diff -up firewalld-0.3.9/src/firewall/core/fw_direct.py.RHBZ#993650 firewalld-0.3.9/src/firewall/core/fw_direct.py --- firewalld-0.3.9/src/firewall/core/fw_direct.py.RHBZ#993650 2013-12-03 14:59:48.000000000 +0100 +++ firewalld-0.3.9/src/firewall/core/fw_direct.py 2014-09-29 22:52:11.977661537 +0200 @@ -55,15 +55,16 @@ class FirewallDirect: self._chains = LastUpdatedOrderedDict() self._rules = LastUpdatedOrderedDict() self._rule_priority_positions = { } + self._passthroughs = LastUpdatedOrderedDict() def cleanup(self): self.__init_vars() def get_config(self): - return (self._chains, self._rules) + return (self._chains, self._rules, self._passthroughs) def set_config(self, config): - (_chains, _rules) = config + (_chains, _rules, _passthroughs) = config for table_id in _chains: (ipv, table) = table_id for chain in _chains[table_id]: @@ -82,6 +83,14 @@ class FirewallDirect: except FirewallError as error: log.warning(str(error)) + for ipv in _passthroughs: + for args in _passthroughs[ipv]: + if not self.query_passthrough(ipv, args): + try: + self.add_passthrough(ipv, args) + except FirewallError as error: + log.warning(str(error)) + # DIRECT CHAIN def __chain(self, add, ipv, table, chain): @@ -268,10 +277,10 @@ class FirewallDirect: for key in self._rules: (ipv, table, chain) = key for (priority, args) in self._rules[key]: - r.append((ipv, table, chain, priority, args)) + r.append((ipv, table, chain, priority, list(args))) return r - # DIRECT PASSTROUGH + # DIRECT PASSTROUGH (untracked) def passthrough(self, ipv, args): try: @@ -279,3 +288,64 @@ class FirewallDirect: except Exception as msg: log.debug2(msg) raise FirewallError(COMMAND_FAILED, msg) + + # DIRECT PASSTROUGH (tracked) + + def _check_ipv(self, ipv): + ipvs = [ 'ipv4', 'ipv6', 'eb' ] + if ipv not in ipvs: + raise FirewallError(INVALID_IPV, + "'%s' not in '%s'" % (ipv, ipvs)) + + def __passthrough(self, enable, ipv, args): + self._check_ipv(ipv) + + passthrough_id = (ipv, args) + if enable: + if ipv in self._passthroughs and args in self._passthroughs[ipv]: + raise FirewallError(ALREADY_ENABLED, + "passthrough '%s', '%s'" % (ipv, args)) + else: + if not ipv in self._passthroughs or \ + args not in self._passthroughs[ipv]: + raise FirewallError(NOT_ENABLED, + "passthrough '%s', '%s'" % (ipv, args)) + + try: + self._fw.rule(ipv, args) + except Exception as msg: + log.debug2(msg) + raise FirewallError(COMMAND_FAILED, msg) + + if enable: + if not ipv in self._passthroughs: + self._passthroughs[ipv] = [ ] + self._passthroughs[ipv].append(args) + else: + self._passthroughs[ipv].remove(args) + if len(self._passthroughs[ipv]) == 0: + del self._passthroughs[ipv] + + def add_passthrough(self, ipv, args): + self.__passthrough(True, ipv, list(args)) + + def remove_passthrough(self, ipv, args): + self.__passthrough(False, ipv, list(args)) + + def query_passthrough(self, ipv, args): + return (ipv in self._passthroughs and \ + list(args) in self._passthroughs[ipv]) + + def get_all_passthroughs(self): + r = [ ] + for ipv in self._passthroughs: + for args in self._passthroughs[ipv]: + r.append((ipv, list(args))) + return r + + def get_passthroughs(self, ipv): + r = [ ] + if ipv in self._passthroughs: + for args in self._passthroughs[ipv]: + r.append(list(args)) + return r diff -up firewalld-0.3.9/src/firewall/core/fw.py.RHBZ#993650 firewalld-0.3.9/src/firewall/core/fw.py --- firewalld-0.3.9/src/firewall/core/fw.py.RHBZ#993650 2014-09-29 22:40:24.027110130 +0200 +++ firewalld-0.3.9/src/firewall/core/fw.py 2014-09-29 22:51:23.763516877 +0200 @@ -211,14 +211,9 @@ class Firewall: log.debug1("Failed to load direct rules file '%s': %s", FIREWALLD_DIRECT, msg) else: - self.direct.set_config((obj.get_all_chains(), obj.get_all_rules())) - for ipv, args in obj.get_all_passthroughs().items(): - for arg in args: - try: - self.direct.passthrough(ipv, arg) - except FirewallError as error: - log.warning(str(error)) - # TODO: copy obj into config interface + self.direct.set_config((obj.get_all_chains(), + obj.get_all_rules(), + obj.get_all_passthroughs())) self.config.set_direct(copy.deepcopy(obj)) # check if default_zone is a valid zone diff -up firewalld-0.3.9/src/firewall/core/io/direct.py.RHBZ#993650 firewalld-0.3.9/src/firewall/core/io/direct.py --- firewalld-0.3.9/src/firewall/core/io/direct.py.RHBZ#993650 2014-09-29 22:40:24.035110167 +0200 +++ firewalld-0.3.9/src/firewall/core/io/direct.py 2014-09-29 22:41:16.197349211 +0200 @@ -25,7 +25,7 @@ import io import shutil from firewall.fw_types import * -from firewall.functions import splitArgs, joinArgs +from firewall.functions import splitArgs, joinArgs, u2b_if_py2 from firewall.errors import * from firewall.core.io.io_object import * from firewall.core.logger import log @@ -50,7 +50,8 @@ class direct_ContentHandler(IO_Object_Co ipv = attrs["ipv"] table = attrs["table"] chain = attrs["chain"] - self.item.add_chain(ipv, table, chain) + self.item.add_chain(u2b_if_py2(ipv), u2b_if_py2(table), + u2b_if_py2(chain)) elif name == "rule": if not self.direct: @@ -67,14 +68,15 @@ class direct_ContentHandler(IO_Object_Co log.error("Parse Error: %s is not a valid priority" % attrs["priority"]) return - self._rule = [ipv, table, chain, priority] + self._rule = [ u2b_if_py2(ipv), u2b_if_py2(table), + u2b_if_py2(chain), priority ] elif name == "passthrough": if not self.direct: log.error("Parse Error: command outside of direct") return ipv = attrs["ipv"] - self._passthrough = [ipv] + self._passthrough = [ u2b_if_py2(ipv) ] else: log.error('Unknown XML element %s' % name) @@ -86,7 +88,7 @@ class direct_ContentHandler(IO_Object_Co if name == "rule": if self._element: # add arguments - self._rule.append(splitArgs(self._element)) + self._rule.append([ u2b_if_py2(x) for x in splitArgs(self._element) ]) self.item.add_rule(*self._rule) else: log.error("Error: rule does not have any arguments, ignoring.") @@ -94,7 +96,7 @@ class direct_ContentHandler(IO_Object_Co elif name == "passthrough": if self._element: # add arguments - self._passthrough.append(splitArgs(self._element)) + self._passthrough.append([ u2b_if_py2(x) for x in splitArgs(self._element) ]) self.item.add_passthrough(*self._passthrough) else: log.error("Error: passthrough does not have any arguments, " + diff -up firewalld-0.3.9/src/firewall/core/io/lockdown_whitelist.py.RHBZ#993650 firewalld-0.3.9/src/firewall/core/io/lockdown_whitelist.py --- firewalld-0.3.9/src/firewall/core/io/lockdown_whitelist.py.RHBZ#993650 2014-09-29 22:40:23.962109823 +0200 +++ firewalld-0.3.9/src/firewall/core/io/lockdown_whitelist.py 2014-09-29 22:41:16.197349211 +0200 @@ -142,9 +142,9 @@ class LockdownWhitelist(IO_Object): """ HACK. I haven't been able to make sax parser return strings encoded (because of python 2) instead of in unicode. Get rid of it once we throw out python 2 support.""" - self.commands = u2b_if_py2(self.commands) - self.contexts = u2b_if_py2(self.contexts) - self.users = u2b_if_py2(self.users) + self.commands = [ u2b_if_py2(x) for x in self.commands ] + self.contexts = [ u2b_if_py2(x) for x in self.contexts ] + self.users = [ u2b_if_py2(x) for x in self.users ] # commands diff -up firewalld-0.3.9/src/firewall/errors.py.RHBZ#993650 firewalld-0.3.9/src/firewall/errors.py --- firewalld-0.3.9/src/firewall/errors.py.RHBZ#993650 2013-12-03 14:59:48.000000000 +0100 +++ firewalld-0.3.9/src/firewall/errors.py 2014-09-29 22:41:16.197349211 +0200 @@ -39,6 +39,7 @@ NAME_MISMATCH = 27 PARSE_ERROR = 28 ACCESS_DENIED = 29 UNKNOWN_SOURCE = 30 +RT_TO_PERM_FAILED = 31 INVALID_ACTION = 100 INVALID_SERVICE = 101 diff -up firewalld-0.3.9/src/firewall/server/firewalld.py.RHBZ#993650 firewalld-0.3.9/src/firewall/server/firewalld.py --- firewalld-0.3.9/src/firewall/server/firewalld.py.RHBZ#993650 2014-09-29 22:40:23.973109875 +0200 +++ firewalld-0.3.9/src/firewall/server/firewalld.py 2014-09-29 22:54:13.271031417 +0200 @@ -259,6 +259,120 @@ class FirewallD(slip.dbus.service.Object def Reloaded(self): log.debug1("Reloaded()") + # runtime to permanent + + @slip.dbus.polkit.require_auth(PK_ACTION_CONFIG) + @dbus_service_method(DBUS_INTERFACE, in_signature='', out_signature='') + @dbus_handle_exceptions + def runtimeToPermanent(self, sender=None): + """Make runtime configuration permanent + """ + log.debug1("copyRuntimeToPermanent()") + + # Services or icmptypes can not be modified in runtime, but they can + # be removed or modified in permanent environment. Therefore copying + # of services and icmptypes to permanent is also needed. + + # services + + for name in self.fw.service.get_services(): + config = self.getServiceSettings(name) + try: + try: + conf_obj = self.config.getServiceByName(name) + except FirewallError as e: + if "INVALID_SERVICE" in e: + log.debug1("Creating service '%s'" % name) + self.config.addService(name, config) + else: + raise + else: + if conf_obj.getSettings() != config: + log.debug1("Copying service '%s' settings" % name) + conf_obj.update(config) + else: + log.debug1("Service '%s' is identical" % name) + except Exception as e: + raise FirewallError(RT_TO_PERM_FAILED, + "service '%s' : %s" % (name, e)) + + # icmptypes + + for name in self.fw.icmptype.get_icmptypes(): + config = self.getIcmpTypeSettings(name) + try: + try: + conf_obj = self.config.getIcmpTypeByName(name) + except FirewallError as e: + if "INVALID_ICMPTYPE" in e: + log.debug1("Creating icmptype '%s'" % name) + self.config.addIcmpType(name, config) + else: + raise + else: + if conf_obj.getSettings() != config: + log.debug1("Copying icmptype '%s' settings" % name) + conf_obj.update(config) + else: + log.debug1("IcmpType '%s' is identical" % name) + except Exception as e: + raise FirewallError(RT_TO_PERM_FAILED, + "icmptype '%s' : %s" % (name, e)) + + # zones + + for name in self.fw.zone.get_zones(): + # zone runtime settings can be modified, but not service and + # icmptye settings + config = self.getZoneSettings(name) + try: + try: + conf_obj = self.config.getZoneByName(name) + except FirewallError as e: + if "INVALID_ZONE" in e: + log.debug1("Creating zone '%s'" % name) + self.config.addZone(name, config) + else: + raise + else: + if conf_obj.getSettings() != config: + log.debug1("Copying zone '%s' settings" % name) + conf_obj.update(config) + else: + log.debug1("Zone '%s' is identical" % name) + except Exception as e: + raise FirewallError(RT_TO_PERM_FAILED, + "zone '%s' : %s" % (name, e)) + + # direct + + # rt_config = self.fw.direct.get_config() + config = ( self.fw.direct.get_all_chains(), + self.fw.direct.get_all_rules(), + self.fw.direct.get_all_passthroughs() ) + try: + if self.config.getSettings() != config: + log.debug1("Copying direct configuration") + self.config.update(config) + else: + log.debug1("Direct configuration is identical") + except Exception as e: + raise FirewallError(RT_TO_PERM_FAILED, + "direct configuration: %s" % e) + + # policies + + config = self.fw.policies.lockdown_whitelist.export_config() + try: + if self.config.getSettings() != config: + log.debug1("Copying policies configuration") + self.config.setLockdownWhitelist(config) + else: + log.debug1("Policies configuration is identical") + except Exception as e: + raise FirewallError(RT_TO_PERM_FAILED, + "policies configuration: %s" % e) + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # POLICIES # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # @@ -1665,7 +1779,7 @@ class FirewallD(slip.dbus.service.Object # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # - # DIRECT PASSTHROUGH + # DIRECT PASSTHROUGH (untracked) @slip.dbus.polkit.require_auth(PK_ACTION_DIRECT) @dbus_service_method(DBUS_INTERFACE_DIRECT, in_signature='sas', @@ -1678,3 +1792,84 @@ class FirewallD(slip.dbus.service.Object log.debug1("direct.passthrough('%s', '%s')" % (ipv, "','".join(args))) self.accessCheck(sender) return self.fw.direct.passthrough(ipv, args) + + # DIRECT PASSTHROUGH (tracked) + + @dbus_service_method(DBUS_INTERFACE_DIRECT, in_signature='sas', + out_signature='') + @dbus_handle_exceptions + def addPassthrough(self, ipv, args, sender=None): + # inserts direct passthrough + ipv = dbus_to_python(ipv) + args = tuple( dbus_to_python(i) for i in args ) + log.debug1("direct.addPassthrough('%s', '%s')" % \ + (ipv, "','".join(args))) + self.accessCheck(sender) + self.fw.direct.add_passthrough(ipv, args) + self.PassthroughAdded(ipv, args) + + @dbus_service_method(DBUS_INTERFACE_DIRECT, in_signature='sas', + out_signature='') + @dbus_handle_exceptions + def removePassthrough(self, ipv, args, sender=None): + # removes direct passthrough + ipv = dbus_to_python(ipv) + args = tuple( dbus_to_python(i) for i in args ) + log.debug1("direct.removePassthrough('%s', '%s')" % \ + (ipv, "','".join(args))) + self.accessCheck(sender) + self.fw.direct.remove_passthrough(ipv, args) + self.PassthroughRemoved(ipv, args) + + @slip.dbus.polkit.require_auth(PK_ACTION_DIRECT) + @dbus_service_method(DBUS_INTERFACE_DIRECT, in_signature='sas', + out_signature='b') + @dbus_handle_exceptions + def queryPassthrough(self, ipv, args, sender=None): + # returns true if a passthrough is enabled + ipv = dbus_to_python(ipv) + args = tuple( dbus_to_python(i) for i in args ) + log.debug1("direct.queryPassthrough('%s', '%s')" % \ + (ipv, "','".join(args))) + return self.fw.direct.query_passthrough(ipv, args) + + @slip.dbus.polkit.require_auth(PK_ACTION_DIRECT) + @dbus_service_method(DBUS_INTERFACE_DIRECT, in_signature='', + out_signature='a(sas)') + @dbus_handle_exceptions + def getAllPassthroughs(self, sender=None): + # returns list of all added passthroughs + log.debug1("direct.getAllPassthroughs()") + return self.fw.direct.get_all_passthroughs() + + @slip.dbus.polkit.require_auth(PK_ACTION_DIRECT) + @dbus_service_method(DBUS_INTERFACE_DIRECT, in_signature='', + out_signature='') + @dbus_handle_exceptions + def removeAllPassthroughs(self, sender=None): + # remove all passhroughs + log.debug1("direct.removeAllPassthroughs()") + for passthrough in self.getAllPassthroughs(): + self.removePassthrough(*passthrough) + + @slip.dbus.polkit.require_auth(PK_ACTION_DIRECT) + @dbus_service_method(DBUS_INTERFACE_DIRECT, in_signature='s', + out_signature='aas') + @dbus_handle_exceptions + def getPassthroughs(self, ipv, sender=None): + # returns list of all added passthroughs with ipv + ipv = dbus_to_python(ipv) + log.debug1("direct.getPassthroughs('%s')", ipv) + return self.fw.direct.get_passthroughs(ipv) + + @dbus.service.signal(DBUS_INTERFACE_DIRECT, signature='sas') + @dbus_handle_exceptions + def PassthroughAdded(self, ipv, args): + log.debug1("direct.PassthroughAdded('%s', '%s')" % \ + (ipv, "','".join(args))) + + @dbus.service.signal(DBUS_INTERFACE_DIRECT, signature='sas') + @dbus_handle_exceptions + def PassthroughRemoved(self, ipv, args): + log.debug1("direct.PassthroughRemoved('%s', '%s')" % \ + (ipv, "','".join(args)))