Blame SOURCES/firewalld-0.3.9-RHBZ#993650.patch

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