From de7aa3b619f05f9c7df7e943d899e973fa8ac904 Mon Sep 17 00:00:00 2001 From: Michael Rash Date: Sun, 15 Jul 2012 21:32:14 -0400 Subject: [PATCH] Add INPUT ACCEPT rule for --nat-local connections When using the --nat-local argument on the fwknop client command line, the fwknopd server needs to add an INPUT ACCEPT rule for the requested access since the incoming connection is destined for a local socket. Added test suite support to test --nat-local access. [test suite] Minor bug fix to ensure that all file_find_regex() calls return true if all regex's are matched and false if any regex does not match data in the specified file. --- client/fwknop.c | 23 ++++++-------- server/fw_util_iptables.c | 43 +++++++++++++++++++++++++ test/test-fwknop.pl | 67 +++++++++++++++++++++++++-------------- 3 files changed, 97 insertions(+), 36 deletions(-) diff --git a/client/fwknop.c b/client/fwknop.c index 687f5a04..040c3ff6 100644 --- a/client/fwknop.c +++ b/client/fwknop.c @@ -664,22 +664,19 @@ set_message_type(fko_ctx_t ctx, fko_cli_options_t *options) { message_type = FKO_COMMAND_MSG; } + else if(options->nat_local) + { + if (options->fw_timeout >= 0) + message_type = FKO_CLIENT_TIMEOUT_LOCAL_NAT_ACCESS_MSG; + else + message_type = FKO_LOCAL_NAT_ACCESS_MSG; + } else if(options->nat_access_str[0] != 0x0) { - if (options->nat_local) - { - if (options->fw_timeout >= 0) - message_type = FKO_CLIENT_TIMEOUT_LOCAL_NAT_ACCESS_MSG; - else - message_type = FKO_LOCAL_NAT_ACCESS_MSG; - } + if (options->fw_timeout >= 0) + message_type = FKO_CLIENT_TIMEOUT_NAT_ACCESS_MSG; else - { - if (options->fw_timeout >= 0) - message_type = FKO_CLIENT_TIMEOUT_NAT_ACCESS_MSG; - else - message_type = FKO_NAT_ACCESS_MSG; - } + message_type = FKO_NAT_ACCESS_MSG; } else { diff --git a/server/fw_util_iptables.c b/server/fw_util_iptables.c index a1a36ec3..555eef21 100644 --- a/server/fw_util_iptables.c +++ b/server/fw_util_iptables.c @@ -650,6 +650,49 @@ process_spa_request(const fko_srv_options_t *opts, const acc_stanza_t *acc, spa_ nat_port = atoi(ndx+1); } } + + if(spadat->message_type == FKO_LOCAL_NAT_ACCESS_MSG) + { + /* Need to add an ACCEPT rule into the INPUT chain + */ + zero_cmd_buffers(); + + snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " IPT_ADD_RULE_ARGS, + opts->fw_config->fw_command, + in_chain->table, + in_chain->to_chain, + fst_proto, + spadat->use_src_ip, + nat_port, + exp_ts, + in_chain->target + ); + + res = run_extcmd(cmd_buf, err_buf, CMD_BUFSIZE, 0); + + if (opts->verbose) + log_msg(LOG_INFO, "process_spa_request() CMD: '%s' (res: %d, err: %s)", + cmd_buf, res, err_buf); + + if(EXTCMD_IS_SUCCESS(res)) + { + log_msg(LOG_INFO, "Added Rule to %s for %s, %s expires at %u", + in_chain->to_chain, spadat->use_src_ip, + spadat->spa_message_remain, exp_ts + ); + + in_chain->active_rules++; + + /* Reset the next expected expire time for this chain if it + * is warranted. + */ + if(in_chain->next_expire < now || exp_ts < in_chain->next_expire) + in_chain->next_expire = exp_ts; + } + else + log_msg(LOG_ERR, "Error %i from cmd:'%s': %s", res, cmd_buf, err_buf); + + } /* Make our FORWARD and NAT rules */ diff --git a/test/test-fwknop.pl b/test/test-fwknop.pl index ae9a6420..447d2c06 100755 --- a/test/test-fwknop.pl +++ b/test/test-fwknop.pl @@ -27,6 +27,7 @@ my $future_expired_access_conf = "$conf_dir/future_expired_stanza_access.conf"; my $expired_epoch_access_conf = "$conf_dir/expired_epoch_stanza_access.conf"; my $invalid_expire_access_conf = "$conf_dir/invalid_expire_access.conf"; my $force_nat_access_conf = "$conf_dir/force_nat_access.conf"; +my $local_nat_fwknopd_conf = "$conf_dir/local_nat_fwknopd.conf"; my $dual_key_usage_access_conf = "$conf_dir/dual_key_usage_access.conf"; my $gpg_access_conf = "$conf_dir/gpg_access.conf"; my $default_digest_file = "$run_dir/digest.cache"; @@ -931,7 +932,6 @@ my @tests = ( 'server_conf' => $nat_conf, 'fatal' => $NO }, - { 'category' => 'Rijndael SPA', 'subcategory' => 'client+server', @@ -949,7 +949,24 @@ my @tests = ( 'server_conf' => $nat_conf, 'fatal' => $NO }, - + { + 'category' => 'Rijndael SPA', + 'subcategory' => 'client+server', + 'detail' => "local NAT $force_nat_host (tcp/22 ssh)", + 'err_msg' => "could not complete NAT SPA cycle", + 'function' => \&spa_cycle, + 'cmdline' => "$default_client_args --nat-local", + 'fwknopd_cmdline' => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " . + "$fwknopdCmd -c $local_nat_fwknopd_conf -a $force_nat_access_conf " . + "-d $default_digest_file -p $default_pid_file $intf_str", + 'server_positive_output_matches' => [qr/to\:$force_nat_host\:22/i, + qr/FWKNOP_INPUT.*dport\s22.*\sACCEPT/], + 'server_negative_output_matches' => [qr/to\:$internal_nat_host\:22/i], + 'fw_rule_created' => $NEW_RULE_REQUIRED, + 'fw_rule_removed' => $NEW_RULE_REMOVED, + 'server_conf' => $nat_conf, + 'fatal' => $NO + }, { 'category' => 'Rijndael SPA', 'subcategory' => 'client+server', @@ -1490,7 +1507,8 @@ sub compile_warnings() { ### look for compilation warnings - something like: ### warning: ‘test’ is used uninitialized in this function - return 0 if &file_find_regex([qr/\swarning:\s/, qr/gcc\:.*\sunused/], $current_test_file); + return 0 if &file_find_regex([qr/\swarning:\s/, qr/gcc\:.*\sunused/], + $current_test_file); ### the new binaries should exist unless (-e $fwknopCmd and -x $fwknopCmd) { @@ -2089,7 +2107,7 @@ sub client_server_interaction() { if (&is_fwknopd_running()) { &stop_fwknopd(); - unless (&file_find_regex([qr/Got\sSIGTERM/, qr/^Terminated/], + unless (&file_find_regex([qr/Got\sSIGTERM/], $server_test_file)) { $server_was_stopped = 0; } @@ -2702,34 +2720,37 @@ sub stop_fwknopd() { sub file_find_regex() { my ($re_ar, $file) = @_; - my $found = 0; + my $found_all_regexs = 1; my @write_lines = (); + my @file_lines = (); open F, "< $file" or die "[*] Could not open $file: $!"; - LINE: while () { - my $line = $_; - next LINE if $line =~ /file_file_regex\(\)/; - for my $re (@$re_ar) { - if ($line =~ $re) { - push @write_lines, "[.] file_find_regex() " . - "Matched '$re' with line: $line"; - $found = 1; - last LINE; - } - } + while () { + push @file_lines, $_; } close F; - if ($found) { - for my $line (@write_lines) { - &write_test_file($line, $file); + for my $re (@$re_ar) { + my $matched = 0; + for my $line (@file_lines) { + if ($line =~ $re) { + push @write_lines, "[.] file_find_regex() " . + "Matched '$re' with line: $line"; + $matched = 1; + } + } + unless ($matched) { + push @write_lines, "[.] file_find_regex() " . + "Did not match any regex in '@$re_ar' in file: $file\n"; + $found_all_regexs = 0; } - } else { - &write_test_file("[.] find_find_regex() Did not " . - "match any regex in: '@$re_ar'\n", $file); } - return $found; + for my $line (@write_lines) { + &write_test_file($line, $file); + } + + return $found_all_regexs; } sub find_command() {