diff --git a/test/test-fwknop.pl b/test/test-fwknop.pl index 539ce0e1..cd4173ff 100755 --- a/test/test-fwknop.pl +++ b/test/test-fwknop.pl @@ -1,17 +1,20 @@ #!/usr/bin/perl -w use IO::Socket; +use Data::Dumper; use Getopt::Long 'GetOptions'; use strict; #==================== config ===================== -my $logfile = 'test.log'; +my $logfile = 'test.log'; my $local_key_file = 'local_spa.key'; -my $output_dir = 'output'; -my $lib_dir = '../lib/.libs'; -my $conf_dir = 'conf'; -my $run_dir = 'run'; +my $output_dir = 'output'; +my $lib_dir = '../lib/.libs'; +my $conf_dir = 'conf'; +my $run_dir = 'run'; my $configure_path = '../configure'; +my $cmd_out_tmp = 'cmd.out'; +my $server_cmd_tmp = 'server_cmd.out'; my $default_conf = "$conf_dir/default_fwknopd.conf"; my $default_access_conf = "$conf_dir/default_access.conf"; @@ -471,6 +474,17 @@ my @tests = ( "-i $loopback_intf --foreground --verbose", 'fatal' => $NO }, + { + 'category' => 'Rijndael SPA ops', + 'subcategory' => 'client+server', + 'detail' => 'replay attack detection', + 'err_msg' => 'could not detect replay attack', + 'function' => \&replay_detection_rijndael, + 'cmdline' => $default_client_args, + 'fwknopd_cmdline' => "$fwknopdCmd $default_server_conf_args " . + "-i $loopback_intf --foreground --verbose", + 'fatal' => $NO + }, ); @@ -544,12 +558,12 @@ sub process_include_exclude() { if (@tests_to_include) { my $found = 0; for my $test (@tests_to_include) { - if ($test_hr->{'category'} =~ /$test)/) { + if ($test_hr->{'category'} =~ /$test/) { $found = 1; last; } } - return 1 unless $found; + return 0 unless $found; } if (@tests_to_exclude) { my $found = 0; @@ -572,16 +586,16 @@ sub compile_warnings() { unless $username; return 0 unless &run_cmd("$sudo_path -u $username make -C .. clean", - $current_test_file); + $cmd_out_tmp, $current_test_file); return 0 unless &run_cmd("$sudo_path -u $username make -C ..", - $current_test_file); + $cmd_out_tmp, $current_test_file); } else { return 0 unless &run_cmd('make -C .. clean', - $current_test_file); + $cmd_out_tmp, $current_test_file); return 0 unless &run_cmd('make -C ..', - $current_test_file); + $cmd_out_tmp, $current_test_file); } @@ -621,7 +635,7 @@ sub expected_code_version() { if ($line =~ /(\d.*\d)/) { my $version = $1; return 0 unless &run_cmd($test_hr->{'cmdline'}, - $current_test_file); + $cmd_out_tmp, $current_test_file); return 1 if &file_find_regex([qr/$version/], $current_test_file); } return 0; @@ -631,7 +645,7 @@ sub dump_config() { my $test_hr = shift; return 0 unless &run_cmd($test_hr->{'cmdline'}, - $current_test_file); + $cmd_out_tmp, $current_test_file); ### search for one of the config vars (basic check) return 0 unless &file_find_regex([qr/SYSLOG_IDENTITY/], @@ -644,7 +658,7 @@ sub override_config() { my $test_hr = shift; return 0 unless &run_cmd($test_hr->{'cmdline'}, - $current_test_file); + $cmd_out_tmp, $current_test_file); ### search for the altered config value return 0 unless &file_find_regex([qr/ENABLE_PCAP_PROMISC.*\'Y\'/], @@ -657,7 +671,7 @@ sub non_get_key_path() { my $test_hr = shift; return 0 if &run_cmd($test_hr->{'cmdline'}, - $current_test_file); + $cmd_out_tmp, $current_test_file); return 0 unless &file_find_regex([qr/could\snot\sopen/i], $current_test_file); return 1; @@ -667,7 +681,7 @@ sub no_allow_ip() { my $test_hr = shift; return 0 if &run_cmd($test_hr->{'cmdline'}, - $current_test_file); + $cmd_out_tmp, $current_test_file); return 0 unless &file_find_regex([qr/must\suse\sone\sof/i], $current_test_file); return 1; @@ -677,7 +691,7 @@ sub invalid_allow_ip() { my $test_hr = shift; return 0 if &run_cmd($test_hr->{'cmdline'}, - $current_test_file); + $cmd_out_tmp, $current_test_file); return 0 unless &file_find_regex([qr/Invalid\sallow\sIP\saddress/i], $current_test_file); return 1; @@ -687,7 +701,7 @@ sub invalid_proto() { my $test_hr = shift; return 0 if &run_cmd($test_hr->{'cmdline'}, - $current_test_file); + $cmd_out_tmp, $current_test_file); return 0 unless &file_find_regex([qr/Invalid\sSPA\saccess\smessage/i], $current_test_file); return 1; @@ -699,7 +713,7 @@ sub generate_spa_packet() { &write_key('fwknoptest', $local_key_file); return 0 unless &run_cmd($test_hr->{'cmdline'}, - $current_test_file); + $cmd_out_tmp, $current_test_file); return 0 unless &file_find_regex([qr/final\spacked/i], $current_test_file); @@ -726,17 +740,34 @@ sub basic_rijndael_spa() { return $rv; } -sub server_start() { +sub replay_detection_rijndael() { my $test_hr = shift; - my $rv = &client_server_interaction($test_hr, [], - $USE_PREDEF_PKTS, $NO_FW_RULE, $NO_FORCE_STOP); + ### do a complete SPA cycle and then parse the SPA packet out of the + ### current test file and re-send - unless (&file_find_regex([qr/Starting\sfwknopd\smain\sevent\sloop/], - $server_output_file)) { - $rv = 0; + return 0 unless &basic_rijndael_spa($test_hr); + + my $spa_pkt = &get_spa_packet_from_file($current_test_file); + + unless ($spa_pkt) { + &write_test_file("[-] could not get SPA packet " . + "from file: $current_test_file\n"); + return 0; } + my @packets = ( + { + 'proto' => 'udp', + 'port' => $default_spa_port, + 'dst_ip' => $loopback_ip, + 'data' => $spa_pkt, + }, + ); + + my $rv = &client_server_interaction($test_hr, \@packets, + $USE_PREDEF_PKTS, $NO_FW_RULE, $NO_FORCE_STOP); + if (&is_fwknopd_running()) { &stop_fwknopd(); unless (&file_find_regex([qr/Got\sSIGTERM/], @@ -748,6 +779,36 @@ sub server_start() { $rv = 0; } + unless (&file_find_regex([qr/Replay\sdetected\sfrom\ssource\sIP/i], + $server_output_file)) { + $rv = 0; + } + + return $rv; +} + +sub server_start() { + my $test_hr = shift; + + my $rv = &client_server_interaction($test_hr, [], + $USE_PREDEF_PKTS, $NO_FW_RULE, $NO_FORCE_STOP); + + if (&is_fwknopd_running()) { + &stop_fwknopd(); + unless (&file_find_regex([qr/Got\sSIGTERM/], + $server_output_file)) { + $rv = 0; + } + } else { + &write_test_file("[-] server is not running.\n"); + $rv = 0; + } + + unless (&file_find_regex([qr/Starting\sfwknopd\smain\sevent\sloop/], + $server_output_file)) { + $rv = 0; + } + return $rv; } @@ -757,11 +818,6 @@ sub server_stop() { my $rv = &client_server_interaction($test_hr, [], $USE_PREDEF_PKTS, $NO_FW_RULE, $NO_FORCE_STOP); - unless (&file_find_regex([qr/Starting\sfwknopd\smain\sevent\sloop/], - $server_output_file)) { - $rv = 0; - } - if (&is_fwknopd_running()) { &stop_fwknopd(); unless (&file_find_regex([qr/Got\sSIGTERM/], @@ -864,7 +920,7 @@ sub client_server_interaction() { sleep 1; unless (&run_cmd("$fwknopdCmd $default_server_conf_args " . "--fw-list | grep $fake_ip |grep _exp_", - $current_test_file)) { + $cmd_out_tmp, $current_test_file)) { $rv = 0; } } @@ -891,9 +947,39 @@ sub client_server_interaction() { return $rv; } +sub get_spa_packet_from_file() { + my $file = shift; + + my $spa_pkt = ''; + + my $found_trigger_line = 0; + open F, "< $file" or die "[*] Could not open file $file: $!"; + while () { + if (/final\spacked/i) { + $found_trigger_line = 1; + next; + } + next unless $found_trigger_line; + + ### the next line with non whitespace is the SPA packet + if (/(\S+)/) { + $spa_pkt = $1; + last; + } + } + close F; + + return $spa_pkt; +} + sub send_packets() { my $pkts_ar = shift; + open F, ">> $current_test_file" or die $!; + print F "[+] send_packets(): Sending the following packets...\n"; + print F Dumper $pkts_ar; + close F; + for my $pkt_hr (@$pkts_ar) { if ($pkt_hr->{'proto'} eq 'tcp' or $pkt_hr->{'proto'} eq 'udp') { my $socket = IO::Socket::INET->new( @@ -922,7 +1008,7 @@ sub fw_list() { my $test_hr = shift; return 0 unless &run_cmd($test_hr->{'cmdline'}, - $current_test_file); + $cmd_out_tmp, $current_test_file); return 1; } @@ -930,7 +1016,7 @@ sub fw_list_all() { my $test_hr = shift; return 0 unless &run_cmd($test_hr->{'cmdline'}, - $current_test_file); + $cmd_out_tmp, $current_test_file); return 1; } @@ -938,7 +1024,7 @@ sub fw_flush() { my $test_hr = shift; return 0 unless &run_cmd($test_hr->{'cmdline'}, - $current_test_file); + $cmd_out_tmp, $current_test_file); return 1; } @@ -946,7 +1032,7 @@ sub usage_info() { my $test_hr = shift; return 0 unless $test_hr->{'binary'}; return 0 unless &run_cmd("$test_hr->{'binary'} -h", - $current_test_file); + $cmd_out_tmp, $current_test_file); return 1; } @@ -954,7 +1040,7 @@ sub no_such_arg() { my $test_hr = shift; return 0 unless $test_hr->{'binary'}; return 0 if &run_cmd("$test_hr->{'binary'} --no-such-arg", - $current_test_file); + $cmd_out_tmp, $current_test_file); return 1; } @@ -963,7 +1049,7 @@ sub pie_binary() { my $test_hr = shift; return 0 unless $test_hr->{'binary'}; &run_cmd("./hardening-check $test_hr->{'binary'}", - $current_test_file); + $cmd_out_tmp, $current_test_file); return 0 if &file_find_regex([qr/Position\sIndependent.*:\sno/i], $current_test_file); return 1; @@ -974,7 +1060,7 @@ sub stack_protected_binary() { my $test_hr = shift; return 0 unless $test_hr->{'binary'}; &run_cmd("./hardening-check $test_hr->{'binary'}", - $current_test_file); + $cmd_out_tmp, $current_test_file); return 0 if &file_find_regex([qr/Stack\sprotected.*:\sno/i], $current_test_file); return 1; @@ -985,7 +1071,7 @@ sub fortify_source_functions() { my $test_hr = shift; return 0 unless $test_hr->{'binary'}; &run_cmd("./hardening-check $test_hr->{'binary'}", - $current_test_file); + $cmd_out_tmp, $current_test_file); return 0 if &file_find_regex([qr/Fortify\sSource\sfunctions:\sno/i], $current_test_file); return 1; @@ -996,7 +1082,7 @@ sub read_only_relocations() { my $test_hr = shift; return 0 unless $test_hr->{'binary'}; &run_cmd("./hardening-check $test_hr->{'binary'}", - $current_test_file); + $cmd_out_tmp, $current_test_file); return 0 if &file_find_regex([qr/Read.only\srelocations:\sno/i], $current_test_file); return 1; @@ -1007,7 +1093,7 @@ sub immediate_binding() { my $test_hr = shift; return 0 unless $test_hr->{'binary'}; &run_cmd("./hardening-check $test_hr->{'binary'}", - $current_test_file); + $cmd_out_tmp, $current_test_file); return 0 if &file_find_regex([qr/Immediate\sbinding:\sno/i], $current_test_file); return 1; @@ -1016,7 +1102,7 @@ sub immediate_binding() { sub specs() { &run_cmd("$fwknopdCmd $default_server_conf_args --fw-list-all", - $current_test_file); + $cmd_out_tmp, $current_test_file); for my $cmd ( 'uname -a', @@ -1036,7 +1122,7 @@ sub specs() { 'ls -l /usr/lib/*fko*', 'ls -l /usr/local/lib/*fko*', ) { - &run_cmd($cmd, $current_test_file); + &run_cmd($cmd, $cmd_out_tmp, $current_test_file); } return 1; } @@ -1071,7 +1157,8 @@ sub start_fwknopd() { if ($pid == 0) { ### we are the child, so start fwknopd - exit &run_cmd($test_hr->{'fwknopd_cmdline'}, $server_output_file); + exit &run_cmd($test_hr->{'fwknopd_cmdline'}, + $server_cmd_tmp, $server_output_file); } return $pid; } @@ -1092,12 +1179,13 @@ sub dump_pids() { or die "[*] Could not open $current_test_file: $!"; print C "\n" . localtime() . " [+] PID dump:\n"; close C; - &run_cmd("ps auxww | grep knop |grep -v grep", $current_test_file); + &run_cmd("ps auxww | grep knop |grep -v grep", + $cmd_out_tmp, $current_test_file); return; } sub run_cmd() { - my ($cmd, $file) = @_; + my ($cmd, $cmd_out, $file) = @_; if (-e $file) { open F, ">> $file" @@ -1110,7 +1198,17 @@ sub run_cmd() { print F "CMD: $cmd\n"; close F; } - my $rv = ((system "$cmd >> $file 2>&1") >> 8); + + my $rv = ((system "$cmd > $cmd_out 2>&1") >> 8); + + open C, "< $cmd_out" or die "[*] Could not open $cmd_out: $!"; + my @cmd_lines = ; + close C; + + open F, ">> $file" or die "[*] Could not open $file: $!"; + print F $_ for @cmd_lines; + close F; + if ($rv == 0) { return 1; } @@ -1152,6 +1250,7 @@ sub init() { die "[*] $conf_dir directory does not exist." unless -d $conf_dir; die "[*] $lib_dir directory does not exist." unless -d $lib_dir; + die "[*] $run_dir directory does not exist." unless -d $run_dir; die "[*] default config $default_conf does not exist" unless -e $default_conf; die "[*] default access config $default_access_conf does not exist" unless -e $default_access_conf; @@ -1196,25 +1295,21 @@ sub init() { sub is_fwknopd_running() { - my $cmd = "$fwknopdCmd $default_server_conf_args --status"; + &run_cmd("$fwknopdCmd $default_server_conf_args --status", + $cmd_out_tmp, $current_test_file); + + return 0 if &file_find_regex([qr/no\s+running/i], $cmd_out_tmp); - &run_cmd($cmd, $current_test_file); - return 0 if &file_find_regex([qr/no\s+running/i], $current_test_file); return 1; } sub stop_fwknopd() { - my $cmd = "$fwknopdCmd $default_server_conf_args -K"; - &run_cmd($cmd, $current_test_file); + &run_cmd("$fwknopdCmd $default_server_conf_args -K", + $cmd_out_tmp, $current_test_file); sleep 1; - if (&is_fwknopd_running()) { - &write_test_file("[*] stop_fwknopd(): Could not stop fwknopd.\n"); - } else { - &write_test_file("[*] stop_fwknopd(): Successfully stopped fwknopd.\n"); - } return; }