[server] Bug fix for SPA NAT modes on iptables firewalls for chain re-creation
authorMichael Rash <mbr@cipherdyne.org>
Wed, 4 Dec 2013 02:42:23 +0000 (21:42 -0500)
committerMichael Rash <mbr@cipherdyne.org>
Wed, 4 Dec 2013 02:42:23 +0000 (21:42 -0500)
For SPA NAT modes this commit ensures that custom fwknop chains are re-created
if they get deleted out from under the running fwknopd instance.

ChangeLog
server/fw_util_iptables.c
test/test-fwknop.pl
test/tests/rijndael.pl
test/tests/rijndael_hmac.pl

index 57a267d..34f9764 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -26,6 +26,9 @@ fwknop-2.5.2 (//2013):
       recommended to use HMAC authenticated encryption whenever possible even
       for GPG modes since this also provides a work around even for libfko
       prior to this fix.
+    - [server] Bug fix for SPA NAT modes on iptables firewalls to ensure that
+      custom fwknop chains are re-created if they get deleted out from under
+      the running fwknopd instance.
     - [test suite] added --gdb-test to allow a previously executed fwknop
       or fwknopd command to be sent through gdb with the same command line
       args as the test suite used.  This is for convenience to rapidly allow
index 559ca93..8a10304 100644 (file)
@@ -1141,6 +1141,15 @@ process_spa_request(const fko_srv_options_t * const opts,
                 in_chain->target
             );
 
+            /* Check to make sure that the jump rules exist for each
+             * required chain
+            */
+            if(chain_exists(opts, IPT_INPUT_ACCESS) == 0)
+                create_chain(opts, IPT_INPUT_ACCESS);
+
+            if(jump_rule_exists(opts, IPT_INPUT_ACCESS) == 0)
+                add_jump_rule(opts, IPT_INPUT_ACCESS);
+
             if(rule_exists(opts, in_chain, rule_buf,
                         fst_proto, spadat->use_src_ip, nat_port, exp_ts) == 0)
             {
@@ -1207,7 +1216,7 @@ process_spa_request(const fko_srv_options_t * const opts,
 
         if(strlen(dnat_chain->to_chain))
         {
-            /* Make sure the required chain and jump rule exists
+            /* Make sure the required chain and jump rule exist
             */
             if(chain_exists(opts, IPT_DNAT_ACCESS) == 0)
                 create_chain(opts, IPT_DNAT_ACCESS);
@@ -1264,6 +1273,16 @@ process_spa_request(const fko_srv_options_t * const opts,
                 snprintf(snat_target, SNAT_TARGET_BUFSIZE-1,
                     "--to-source %s:%i", opts->config[CONF_SNAT_TRANSLATE_IP],
                     fst_port);
+
+                /* Check to make sure that the jump rules exist for each
+                 * required chain
+                */
+                if(chain_exists(opts, IPT_SNAT_ACCESS) == 0)
+                    create_chain(opts, IPT_SNAT_ACCESS);
+
+                if(jump_rule_exists(opts, IPT_SNAT_ACCESS) == 0)
+                    add_jump_rule(opts, IPT_SNAT_ACCESS);
+
             }
             else
             {
@@ -1271,6 +1290,15 @@ process_spa_request(const fko_srv_options_t * const opts,
                 snat_chain = &(opts->fw_config->chain[IPT_MASQUERADE_ACCESS]);
                 snprintf(snat_target, SNAT_TARGET_BUFSIZE-1,
                     "--to-ports %i", fst_port);
+
+                /* Check to make sure that the jump rules exist for each
+                 * required chain
+                */
+                if(chain_exists(opts, IPT_MASQUERADE_ACCESS) == 0)
+                    create_chain(opts, IPT_MASQUERADE_ACCESS);
+
+                if(jump_rule_exists(opts, IPT_MASQUERADE_ACCESS) == 0)
+                    add_jump_rule(opts, IPT_MASQUERADE_ACCESS);
             }
 
             memset(rule_buf, 0, CMD_BUFSIZE);
index c3f7044..42aef8f 100755 (executable)
@@ -613,6 +613,7 @@ my %test_keys = (
     'mv_and_restore_replay_cache' => $OPTIONAL,
     'server_positive_output_matches' => $OPTIONAL,
     'server_negative_output_matches' => $OPTIONAL,
+    'iptables_rm_chains_after_server_start' => $OPTIONAL,
 );
 
 &validate_test_hashes();
@@ -4497,6 +4498,31 @@ sub client_server_interaction() {
             $cmd_out_tmp, $curr_test_file);
     }
 
+    if ($test_hr->{'iptables_rm_chains_after_server_start'}) {
+        ### this deletes fwknop chains out from under the running fwknopd
+        ### instance (tests whether it is able to recover with
+        ### chain_exists(), etc.)
+        if ($test_hr->{'fwknopd_cmdline'}
+                =~ /LD_LIBRARY_PATH=(\S+)\s.*\s\-c\s(\S+)\s\-a\s(\S+)/) {
+            my $lib_path     = $1;
+            my $fwknopd_conf = $2;
+            my $access_conf  = $3;
+            &write_test_file("[+] fwknopd iptables policy before flush:\n",
+                $curr_test_file);
+            &run_cmd("LD_LIBRARY_PATH=$lib_path $fwknopdCmd -c " .
+                "$fwknopd_conf -a $access_conf --fw-list",
+                $cmd_out_tmp, $curr_test_file);
+            &run_cmd("LD_LIBRARY_PATH=$lib_path $fwknopdCmd -c " .
+                "$fwknopd_conf -a $access_conf --fw-flush",
+                $cmd_out_tmp, $curr_test_file);
+            &write_test_file("[+] fwknopd iptables policy after flush:\n",
+                $curr_test_file);
+            &run_cmd("LD_LIBRARY_PATH=$lib_path $fwknopdCmd -c " .
+                "$fwknopd_conf -a $access_conf --fw-list",
+                $cmd_out_tmp, $curr_test_file);
+        }
+    }
+
     ### send the SPA packet(s) to the server either manually using IO::Socket or
     ### with the fwknopd client
     if ($spa_client_flag == $USE_CLIENT) {
index 2266dbb..a4260f0 100644 (file)
             "-d $default_digest_file -p $default_pid_file $intf_str",
         'server_positive_output_matches' => [
             qr/FWKNOP_FORWARD\s.*dport\s22\s/,
-            qr/to\:$internal_nat_host\:22/i],
+            qr/\*\/\sto\:$internal_nat_host\:22/i],
         'fw_rule_created' => $NEW_RULE_REQUIRED,
         'fw_rule_removed' => $NEW_RULE_REMOVED,
         'server_conf' => $cf{'nat'},
             "-d $default_digest_file -p $default_pid_file $intf_str",
         'server_positive_output_matches' => [
             qr/FWKNOP_FORWARD\s.*dport\s22\s/,
-            qr/to\:$internal_nat_host\:22/i],
+            qr/\*\/\sto\:$internal_nat_host\:22/i],
         'no_ip_check' => 1,
         'fw_rule_created' => $NEW_RULE_REQUIRED,
         'fw_rule_removed' => $NEW_RULE_REMOVED,
             "-d $default_digest_file -p $default_pid_file $intf_str",
         'server_positive_output_matches' => [
             qr/FWKNOP_FORWARD\s.*dport\s22\s/,
-            qr/to\:$internal_nat_host\:22/i,
+            qr/\*\/\sto\:$internal_nat_host\:22/i,
             qr/MASQUERADE\s.*to\-ports/,
         ],
         'no_ip_check' => 1,
             "-d $default_digest_file -p $default_pid_file $intf_str",
         'server_positive_output_matches' => [
             qr/FWKNOP_FORWARD\s.*dport\s22\s/,
-            qr/to\:127.0.0.1\:22/i],
+            qr/\*\/\sto\:127.0.0.1\:22/i],
         'fw_rule_created' => $NEW_RULE_REQUIRED,
         'fw_rule_removed' => $NEW_RULE_REMOVED,
         'server_conf' => $cf{'nat'},
             "-d $default_digest_file -p $default_pid_file $intf_str",
         'server_positive_output_matches' => [
             qr/FWKNOP_FORWARD\s.*dport\s22\s/,
-            qr/to\:$internal_nat_host\:22/i],
+            qr/\*\/\sto\:$internal_nat_host\:22/i],
         'fw_rule_created' => $NEW_RULE_REQUIRED,
         'fw_rule_removed' => $NEW_RULE_REMOVED,
         'server_conf' => $cf{'nat'},
         'cmdline'  => "$default_client_args --nat-local",
         'fwknopd_cmdline' => "$fwknopdCmd -c $cf{'local_nat'} -a $cf{'force_nat_access'} " .
             "-d $default_digest_file -p $default_pid_file $intf_str",
-        'server_positive_output_matches' => [qr/to\:$force_nat_host\:22/i,
+        'server_positive_output_matches' => [qr/\*\/\sto\:$force_nat_host\:22/i,
             qr/FWKNOP_INPUT.*dport\s22.*\sACCEPT/],
-        'server_negative_output_matches' => [qr/to\:$internal_nat_host\:22/i],
+        'server_negative_output_matches' => [qr/\*\/\sto\:$internal_nat_host\:22/i],
         'fw_rule_created' => $NEW_RULE_REQUIRED,
         'fw_rule_removed' => $NEW_RULE_REMOVED,
         'server_conf' => $cf{'local_nat'},
             "--get-key $local_key_file --no-save-args $verbose_str",
         'fwknopd_cmdline' => "$fwknopdCmd -c $cf{'local_nat'} -a $cf{'force_nat_access'} " .
             "-d $default_digest_file -p $default_pid_file $intf_str",
-        'server_positive_output_matches' => [qr/to\:$force_nat_host\:22/i,
+        'server_positive_output_matches' => [qr/\*\/\sto\:$force_nat_host\:22/i,
             qr/FWKNOP_INPUT.*dport\s22.*\sACCEPT/],
-        'server_negative_output_matches' => [qr/to\:$internal_nat_host\:22/i],
+        'server_negative_output_matches' => [qr/\*\/\sto\:$internal_nat_host\:22/i],
         'fw_rule_created' => $NEW_RULE_REQUIRED,
         'fw_rule_removed' => $NEW_RULE_REMOVED,
         'server_conf' => $cf{'local_nat'},
         'cmdline'  => "$default_client_args --nat-local --nat-rand-port",
         'fwknopd_cmdline' => "$fwknopdCmd -c $cf{'local_nat'} -a $cf{'def_access'} " .
             "-d $default_digest_file -p $default_pid_file $intf_str",
-        'server_positive_output_matches' => [qr/to\:$loopback_ip\:22/i,
+        'server_positive_output_matches' => [qr|\s\*\/\sto\:$loopback_ip\:22|i,
             qr/FWKNOP_INPUT.*dport\s22.*\sACCEPT/],
-        'server_negative_output_matches' => [qr/to\:$internal_nat_host\:22/i],
+        'server_negative_output_matches' => [qr/\*\/\sto\:$internal_nat_host\:22/i],
         'fw_rule_created' => $NEW_RULE_REQUIRED,
         'fw_rule_removed' => $NEW_RULE_REMOVED,
         'server_conf' => $cf{'local_nat'},
             "$local_key_file $verbose_str --nat-local --nat-port 80",
         'fwknopd_cmdline' => "$fwknopdCmd -c $cf{'local_nat'} -a $cf{'def_access'} " .
             "-d $default_digest_file -p $default_pid_file $intf_str",
-        'server_positive_output_matches' => [qr/to\:$loopback_ip\:22/i,
+        'server_positive_output_matches' => [qr|\s\*\/\sto\:$loopback_ip\:22|i,
             qr/FWKNOP_INPUT.*dport\s22.*\sACCEPT/],
-        'server_negative_output_matches' => [qr/to\:$internal_nat_host\:22/i],
+        'server_negative_output_matches' => [qr/\*\/\sto\:$internal_nat_host\:22/i],
         'fw_rule_created' => $NEW_RULE_REQUIRED,
         'fw_rule_removed' => $NEW_RULE_REMOVED,
         'server_conf' => $cf{'local_nat'},
index 8e472e5..64eeffa 100644 (file)
             "-d $default_digest_file -p $default_pid_file $intf_str",
         'server_positive_output_matches' => [
             qr/FWKNOP_FORWARD\s.*dport\s22\s/,
-            qr/to\:$internal_nat_host\:22/i],
+            qr/\*\/\sto\:$internal_nat_host\:22/i],
         'fw_rule_created' => $NEW_RULE_REQUIRED,
         'fw_rule_removed' => $NEW_RULE_REMOVED,
         'key_file' => $cf{'rc_hmac_b64_key'},
             "-d $default_digest_file -p $default_pid_file $intf_str",
         'server_positive_output_matches' => [
             qr/FWKNOP_FORWARD\s.*dport\s22\s/,
-            qr/to\:$internal_nat_host\:22/i],
+            qr/\*\/\sto\:$internal_nat_host\:22/i],
         'no_ip_check' => 1,
         'fw_rule_created' => $NEW_RULE_REQUIRED,
         'fw_rule_removed' => $NEW_RULE_REMOVED,
             "-d $default_digest_file -p $default_pid_file $intf_str",
         'server_positive_output_matches' => [
             qr/FWKNOP_FORWARD\s.*dport\s22\s/,
-            qr/to\:$internal_nat_host\:22/i,
+            qr/\*\/\sto\:$internal_nat_host\:22/i,
             qr/MASQUERADE\s.*to\-ports/,
         ],
         'no_ip_check' => 1,
             "-d $default_digest_file -p $default_pid_file $intf_str",
         'server_positive_output_matches' => [
             qr/FWKNOP_FORWARD_TEST\s.*dport\s22\s/,
-            qr/to\:$internal_nat_host\:22/i],
+            qr/\*\/\sto\:$internal_nat_host\:22/i],
         'fw_rule_created' => $NEW_RULE_REQUIRED,
         'fw_rule_removed' => $NEW_RULE_REMOVED,
         'key_file' => $cf{'rc_hmac_b64_key'},
             "-d $default_digest_file -p $default_pid_file $intf_str",
         'server_positive_output_matches' => [
             qr/FWKNOP_FORWARD\s.*dport\s22\s/,
-            qr/to\:$internal_nat_host\:22/i],
+            qr/\*\/\sto\:$internal_nat_host\:22/i],
         'fw_rule_created' => $NEW_RULE_REQUIRED,
         'fw_rule_removed' => $NEW_RULE_REMOVED,
         'server_conf' => $cf{'nat'},
     {
         'category' => 'Rijndael+HMAC',
         'subcategory' => 'client+server',
+        'detail'   => "force NAT (iptables flush)",
+        'function' => \&spa_cycle,
+        'cmdline'  => $default_client_args,
+        'cmdline'  => "$default_client_args_no_get_key --rc-file " .
+            $cf{'rc_hmac_b64_key'},
+        'fwknopd_cmdline' => "$fwknopdCmd -c $cf{'nat'} -a $cf{'hmac_force_nat_access'} " .
+            "-d $default_digest_file -p $default_pid_file $intf_str",
+        'server_positive_output_matches' => [qr/\sto\:$force_nat_host\:22/i],
+        'server_negative_output_matches' => [qr/\sto\:$internal_nat_host\:22/i],
+        'fw_rule_created' => $NEW_RULE_REQUIRED,
+        'fw_rule_removed' => $NEW_RULE_REMOVED,
+        'server_conf' => $cf{'nat'},
+        'key_file' => $cf{'rc_hmac_b64_key'},
+        'iptables_rm_chains_after_server_start' => $YES,
+    },
+    {
+        'category' => 'Rijndael+HMAC',
+        'subcategory' => 'client+server',
         'detail'   => "local NAT $force_nat_host (tcp/22)",
         'function' => \&spa_cycle,
         'cmdline'  => "$default_client_args_no_get_key --rc-file " .
             "$cf{'rc_hmac_b64_key'} --nat-local",
         'fwknopd_cmdline' => "$fwknopdCmd -c $cf{'local_nat'} -a $cf{'hmac_force_nat_access'} " .
             "-d $default_digest_file -p $default_pid_file $intf_str",
-        'server_positive_output_matches' => [qr/to\:$force_nat_host\:22/i,
+        'server_positive_output_matches' => [qr/\*\/\sto\:$force_nat_host\:22/i,
             qr/FWKNOP_INPUT.*dport\s22.*\sACCEPT/],
-        'server_negative_output_matches' => [qr/to\:$internal_nat_host\:22/i],
+        'server_negative_output_matches' => [qr/\*\/\sto\:$internal_nat_host\:22/i],
         'fw_rule_created' => $NEW_RULE_REQUIRED,
         'fw_rule_removed' => $NEW_RULE_REMOVED,
         'server_conf' => $cf{'local_nat'},
     {
         'category' => 'Rijndael+HMAC',
         'subcategory' => 'client+server',
-        'detail'   => "local NAT non-FORCE_NAT",
+        'detail'   => "local NAT (iptables flush)",
+        'function' => \&spa_cycle,
+        'cmdline'  => "$default_client_args_no_get_key --rc-file " .
+            "$cf{'rc_hmac_b64_key'} --nat-local",
+        'fwknopd_cmdline' => "$fwknopdCmd -c $cf{'local_nat'} -a $cf{'hmac_force_nat_access'} " .
+            "-d $default_digest_file -p $default_pid_file $intf_str",
+        'server_positive_output_matches' => [qr/\*\/\sto\:$force_nat_host\:22/i,
+            qr/FWKNOP_INPUT.*dport\s22.*\sACCEPT/],
+        'server_negative_output_matches' => [qr/\*\/\sto\:$internal_nat_host\:22/i],
+        'fw_rule_created' => $NEW_RULE_REQUIRED,
+        'fw_rule_removed' => $NEW_RULE_REMOVED,
+        'server_conf' => $cf{'local_nat'},
+        'key_file' => $cf{'rc_hmac_b64_key'},
+        'iptables_rm_chains_after_server_start' => $YES,
+    },
+    {
+        'category' => 'Rijndael+HMAC',
+        'subcategory' => 'client+server',
+        'detail'   => "local (non-force) NAT",
         'function' => \&spa_cycle,
         'cmdline' => "$fwknopCmd -A tcp/22 -a $fake_ip -D $loopback_ip --rc-file " .
             "$cf{'rc_hmac_b64_key'} $verbose_str --nat-local --nat-port 80",
         'fwknopd_cmdline' => "$fwknopdCmd -c $cf{'local_nat'} -a $cf{'hmac_access'} " .
             "-d $default_digest_file -p $default_pid_file $intf_str",
-        'server_positive_output_matches' => [qr/to\:$loopback_ip\:22/i,
-            qr/FWKNOP_INPUT.*dport\s22.*\sACCEPT/],
-        'server_negative_output_matches' => [qr/to\:$internal_nat_host\:22/i],
+        'server_positive_output_matches' => [qr|\s\*\/\sto\:$loopback_ip\:22|i,
+            qr/ACCEPT\s{2}.*\s0\.0\.0\.0\/0\s+tcp\sdpt\:22\s/],
+        'server_negative_output_matches' => [qr/\*\/\sto\:$internal_nat_host\:22/i],
+        'fw_rule_created' => $NEW_RULE_REQUIRED,
+        'fw_rule_removed' => $NEW_RULE_REMOVED,
+        'server_conf' => $cf{'local_nat'},
+        'key_file' => $cf{'rc_hmac_b64_key'},
+    },
+    {
+        'category' => 'Rijndael+HMAC',
+        'subcategory' => 'client+server',
+        'detail'   => "local (non-force) NAT (ipt flush)",
+        'function' => \&spa_cycle,
+        'cmdline' => "$fwknopCmd -A tcp/22 -a $fake_ip -D $loopback_ip --rc-file " .
+            "$cf{'rc_hmac_b64_key'} $verbose_str --nat-local --nat-port 80",
+        'fwknopd_cmdline' => "$fwknopdCmd -c $cf{'local_nat'} -a $cf{'hmac_access'} " .
+            "-d $default_digest_file -p $default_pid_file $intf_str",
+        'server_positive_output_matches' => [qr|\s\*\/\sto\:$loopback_ip\:22|i,
+            qr/ACCEPT\s{2}.*\s0\.0\.0\.0\/0\s+tcp\sdpt\:22\s/],
+        'server_negative_output_matches' => [qr/\*\/\sto\:$internal_nat_host\:22/i],
         'fw_rule_created' => $NEW_RULE_REQUIRED,
         'fw_rule_removed' => $NEW_RULE_REMOVED,
         'server_conf' => $cf{'local_nat'},
         'key_file' => $cf{'rc_hmac_b64_key'},
+        'iptables_rm_chains_after_server_start' => $YES,
     },
 
     {
             "$cf{'rc_hmac_b64_key'} $verbose_str --nat-local --nat-rand-port",
         'fwknopd_cmdline' => "$fwknopdCmd -c $cf{'local_nat'} -a $cf{'hmac_access'} " .
             "-d $default_digest_file -p $default_pid_file $intf_str",
-        'server_positive_output_matches' => [qr/to\:$loopback_ip\:22/i,
-            qr/FWKNOP_INPUT.*dport\s22.*\sACCEPT/],
-        'server_negative_output_matches' => [qr/to\:$internal_nat_host\:22/i],
+        'server_positive_output_matches' => [qr|\s\*\/\sto\:$loopback_ip\:22|i,
+            qr/ACCEPT\s{2}.*\s0\.0\.0\.0\/0\s+tcp\sdpt\:22\s/],
+        'server_negative_output_matches' => [qr/\*\/\sto\:$internal_nat_host\:22/i],
         'fw_rule_created' => $NEW_RULE_REQUIRED,
         'fw_rule_removed' => $NEW_RULE_REMOVED,
         'server_conf' => $cf{'local_nat'},