Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Fetching contributors…

Cannot retrieve contributors at this time

executable file 4301 lines (3799 sloc) 148.846 kb
#!/usr/bin/perl -w
use Cwd;
use File::Copy;
use File::Path;
use IO::Socket;
use Data::Dumper;
use Getopt::Long 'GetOptions';
use strict;
#==================== config =====================
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 $configure_path = '../configure';
my $cmd_out_tmp = 'cmd.out';
my $server_cmd_tmp = 'server_cmd.out';
my $gpg_client_home_dir = "$conf_dir/client-gpg";
my $gpg_client_home_dir_no_pw = "$conf_dir/client-gpg-no-pw";
my %cf = (
'nat' => "$conf_dir/nat_fwknopd.conf",
'def' => "$conf_dir/default_fwknopd.conf",
'def_access' => "$conf_dir/default_access.conf",
'exp_access' => "$conf_dir/expired_stanza_access.conf",
'future_exp_access' => "$conf_dir/future_expired_stanza_access.conf",
'exp_epoch_access' => "$conf_dir/expired_epoch_stanza_access.conf",
'invalid_exp_access' => "$conf_dir/invalid_expire_access.conf",
'force_nat_access' => "$conf_dir/force_nat_access.conf",
'cmd_access' => "$conf_dir/cmd_access.conf",
'local_nat' => "$conf_dir/local_nat_fwknopd.conf",
'ipfw_active_expire' => "$conf_dir/ipfw_active_expire_equal_fwknopd.conf",
'dual_key_access' => "$conf_dir/dual_key_usage_access.conf",
'gpg_access' => "$conf_dir/gpg_access.conf",
'gpg_no_pw_access' => "$conf_dir/gpg_no_pw_access.conf",
'tcp_server' => "$conf_dir/tcp_server_fwknopd.conf",
'tcp_pcap_filter' => "$conf_dir/tcp_pcap_filter_fwknopd.conf",
'icmp_pcap_filter' => "$conf_dir/icmp_pcap_filter_fwknopd.conf",
'open_ports_access' => "$conf_dir/open_ports_access.conf",
'multi_gpg_access' => "$conf_dir/multi_gpg_access.conf",
'multi_stanza_access' => "$conf_dir/multi_stanzas_access.conf",
'broken_keys_access' => "$conf_dir/multi_stanzas_with_broken_keys.conf",
'open_ports_mismatch' => "$conf_dir/mismatch_open_ports_access.conf",
'require_user_access' => "$conf_dir/require_user_access.conf",
'user_mismatch_access' => "$conf_dir/mismatch_user_access.conf",
'require_src_access' => "$conf_dir/require_src_access.conf",
'no_src_match' => "$conf_dir/no_source_match_access.conf",
'no_subnet_match' => "$conf_dir/no_subnet_source_match_access.conf",
'no_multi_src' => "$conf_dir/no_multi_source_match_access.conf",
'multi_src_access' => "$conf_dir/multi_source_match_access.conf",
'ip_src_match' => "$conf_dir/ip_source_match_access.conf",
'subnet_src_match' => "$conf_dir/ip_source_match_access.conf",
'disable_aging' => "$conf_dir/disable_aging_fwknopd.conf",
'fuzz_source' => "$conf_dir/fuzzing_source_access.conf",
'fuzz_open_ports' => "$conf_dir/fuzzing_open_ports_access.conf",
'fuzz_restrict_ports' => "$conf_dir/fuzzing_restrict_ports_access.conf",
);
my $default_digest_file = "$run_dir/digest.cache";
my $default_pid_file = "$run_dir/fwknopd.pid";
my $fwknopCmd = '../client/.libs/fwknop';
my $fwknopdCmd = '../server/.libs/fwknopd';
my $libfko_bin = "$lib_dir/libfko.so"; ### this is usually a link
my $valgrindCmd = '/usr/bin/valgrind';
my $gpg_server_key = '361BBAD4';
my $gpg_client_key = '6A3FAD56';
my $loopback_ip = '127.0.0.1';
my $fake_ip = '127.0.0.2';
my $internal_nat_host = '192.168.1.2';
my $force_nat_host = '192.168.1.123';
my $default_spa_port = 62201;
my $non_std_spa_port = 12345;
my $spoof_user = 'testuser';
my $spoof_ip = '1.2.3.4';
my $perl_mod_fko_dir = 'FKO';
my $cmd_exec_test_file = '/tmp/fwknoptest';
#================== end config ===================
my $passed = 0;
my $failed = 0;
my $executed = 0;
my $test_include = '';
my @tests_to_include = ();
my $test_exclude = '';
my @tests_to_exclude = ();
my %valgrind_flagged_fcns = ();
my %valgrind_flagged_fcns_unique = ();
my $list_mode = 0;
my $diff_dir1 = '';
my $diff_dir2 = '';
my $loopback_intf = '';
my $anonymize_results = 0;
my $current_test_file = "$output_dir/init";
my $tarfile = 'test_fwknop.tar.gz';
my $server_test_file = '';
my $use_valgrind = 0;
my $valgrind_str = '';
my $enable_client_ip_resolve_test = 0;
my $saved_last_results = 0;
my $diff_mode = 0;
my $fko_obj = ();
my $enable_recompilation_warnings_check = 0;
my $enable_make_distcheck = 0;
my $enable_perl_module_checks = 0;
my $sudo_path = '';
my $platform = '';
my $help = 0;
my $YES = 1;
my $NO = 0;
my $PRINT_LEN = 68;
my $USE_PREDEF_PKTS = 1;
my $USE_CLIENT = 2;
my $REQUIRED = 1;
my $OPTIONAL = 0;
my $NEW_RULE_REQUIRED = 1;
my $REQUIRE_NO_NEW_RULE = 2;
my $NEW_RULE_REMOVED = 1;
my $REQUIRE_NO_NEW_REMOVED = 2;
my $MATCH_ANY = 1;
my $MATCH_ALL = 2;
my $LINUX = 1;
my $FREEBSD = 2;
my $MACOSX = 3;
my $OPENBSD = 4;
my $ip_re = qr|(?:[0-2]?\d{1,2}\.){3}[0-2]?\d{1,2}|; ### IPv4
my @args_cp = @ARGV;
exit 1 unless GetOptions(
'Anonymize-results' => \$anonymize_results,
'fwknop-path=s' => \$fwknopCmd,
'fwknopd-path=s' => \$fwknopdCmd,
'libfko-path=s' => \$libfko_bin,
'loopback-intf=s' => \$loopback_intf,
'test-include=s' => \$test_include,
'include=s' => \$test_include, ### synonym
'test-exclude=s' => \$test_exclude,
'exclude=s' => \$test_exclude, ### synonym
'enable-perl-module-checks' => \$enable_perl_module_checks,
'enable-recompile-check' => \$enable_recompilation_warnings_check,
'enable-ip-resolve' => \$enable_client_ip_resolve_test,
'enable-distcheck' => \$enable_make_distcheck,
'List-mode' => \$list_mode,
'enable-valgrind' => \$use_valgrind,
'valgrind-path=s' => \$valgrindCmd,
'output-dir=s' => \$output_dir,
'diff' => \$diff_mode,
'diff-dir1=s' => \$diff_dir1,
'diff-dir2=s' => \$diff_dir2,
'help' => \$help
);
&usage() if $help;
### create an anonymized tar file of test suite results that can be
### emailed around to assist in debugging fwknop communications
exit &anonymize_results() if $anonymize_results;
&identify_loopback_intf();
$valgrind_str = "$valgrindCmd --leak-check=full " .
"--show-reachable=yes --track-origins=yes" if $use_valgrind;
my $intf_str = "-i $loopback_intf --foreground --verbose --verbose";
my $default_client_args = "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
"$fwknopCmd -A tcp/22 -a $fake_ip -D $loopback_ip --get-key " .
"$local_key_file --verbose --verbose";
my $client_ip_resolve_args = "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
"$fwknopCmd -A tcp/22 -R -D $loopback_ip --get-key " .
"$local_key_file --verbose --verbose";
my $default_client_gpg_args = "$default_client_args " .
"--gpg-recipient-key $gpg_server_key " .
"--gpg-signer-key $gpg_client_key " .
"--gpg-home-dir $gpg_client_home_dir";
my $default_client_gpg_args_no_homedir = "$default_client_args " .
"--gpg-recipient-key $gpg_server_key " .
"--gpg-signer-key $gpg_client_key ";
my $default_server_conf_args = "-c $cf{'def'} -a $cf{'def_access'} " .
"-d $default_digest_file -p $default_pid_file";
my $default_server_gpg_args = "LD_LIBRARY_PATH=$lib_dir " .
"$valgrind_str $fwknopdCmd -c $cf{'def'} " .
"-a $cf{'gpg_access'} $intf_str " .
"-d $default_digest_file -p $default_pid_file";
my $default_server_gpg_args_no_pw = "LD_LIBRARY_PATH=$lib_dir " .
"$valgrind_str $fwknopdCmd -c $cf{'def'} " .
"-a $cf{'gpg_no_pw_access'} $intf_str " .
"-d $default_digest_file -p $default_pid_file";
### point the compiled binaries at the local libary path
### instead of any installed libfko instance
$ENV{'LD_LIBRARY_PATH'} = $lib_dir;
### main array that defines the tests we will run
my @tests = (
{
'category' => 'recompilation',
'detail' => 'recompile and look for compilation warnings',
'err_msg' => 'compile warnings exist',
'function' => \&compile_warnings,
'fatal' => $NO
},
{
'category' => 'make distcheck',
'detail' => 'ensure proper distribution creation',
'err_msg' => 'could not create proper tarball',
'function' => \&make_distcheck,
'fatal' => $NO
},
{
'category' => 'build',
'subcategory' => 'client',
'detail' => 'binary exists',
'err_msg' => 'binary not found',
'function' => \&binary_exists,
'binary' => $fwknopCmd,
'fatal' => $YES
},
{
'category' => 'build security',
'subcategory' => 'client',
'detail' => 'Position Independent Executable (PIE)',
'err_msg' => 'non PIE binary (fwknop client)',
'function' => \&pie_binary,
'binary' => $fwknopCmd,
'fatal' => $NO
},
{
'category' => 'build security',
'subcategory' => 'client',
'detail' => 'stack protected binary',
'err_msg' => 'non stack protected binary (fwknop client)',
'function' => \&stack_protected_binary,
'binary' => $fwknopCmd,
'fatal' => $NO
},
{
'category' => 'build security',
'subcategory' => 'client',
'detail' => 'fortify source functions',
'err_msg' => 'source functions not fortified (fwknop client)',
'function' => \&fortify_source_functions,
'binary' => $fwknopCmd,
'fatal' => $NO
},
{
'category' => 'build security',
'subcategory' => 'client',
'detail' => 'read-only relocations',
'err_msg' => 'no read-only relocations (fwknop client)',
'function' => \&read_only_relocations,
'binary' => $fwknopCmd,
'fatal' => $NO
},
{
'category' => 'build security',
'subcategory' => 'client',
'detail' => 'immediate binding',
'err_msg' => 'no immediate binding (fwknop client)',
'function' => \&immediate_binding,
'binary' => $fwknopCmd,
'fatal' => $NO
},
{
'category' => 'build',
'subcategory' => 'server',
'detail' => 'binary exists',
'err_msg' => 'binary not found',
'function' => \&binary_exists,
'binary' => $fwknopdCmd,
'fatal' => $YES
},
{
'category' => 'build security',
'subcategory' => 'server',
'detail' => 'Position Independent Executable (PIE)',
'err_msg' => 'non PIE binary (fwknopd server)',
'function' => \&pie_binary,
'binary' => $fwknopdCmd,
'fatal' => $NO
},
{
'category' => 'build security',
'subcategory' => 'server',
'detail' => 'stack protected binary',
'err_msg' => 'non stack protected binary (fwknopd server)',
'function' => \&stack_protected_binary,
'binary' => $fwknopdCmd,
'fatal' => $NO
},
{
'category' => 'build security',
'subcategory' => 'server',
'detail' => 'fortify source functions',
'err_msg' => 'source functions not fortified (fwknopd server)',
'function' => \&fortify_source_functions,
'binary' => $fwknopdCmd,
'fatal' => $NO
},
{
'category' => 'build security',
'subcategory' => 'server',
'detail' => 'read-only relocations',
'err_msg' => 'no read-only relocations (fwknopd server)',
'function' => \&read_only_relocations,
'binary' => $fwknopdCmd,
'fatal' => $NO
},
{
'category' => 'build security',
'subcategory' => 'server',
'detail' => 'immediate binding',
'err_msg' => 'no immediate binding (fwknopd server)',
'function' => \&immediate_binding,
'binary' => $fwknopdCmd,
'fatal' => $NO
},
{
'category' => 'build',
'subcategory' => 'libfko',
'detail' => 'binary exists',
'err_msg' => 'binary not found',
'function' => \&binary_exists,
'binary' => $libfko_bin,
'fatal' => $YES
},
{
'category' => 'build security',
'subcategory' => 'libfko',
'detail' => 'stack protected binary',
'err_msg' => 'non stack protected binary (libfko)',
'function' => \&stack_protected_binary,
'binary' => $libfko_bin,
'fatal' => $NO
},
{
'category' => 'build security',
'subcategory' => 'libfko',
'detail' => 'fortify source functions',
'err_msg' => 'source functions not fortified (libfko)',
'function' => \&fortify_source_functions,
'binary' => $libfko_bin,
'fatal' => $NO
},
{
'category' => 'build security',
'subcategory' => 'libfko',
'detail' => 'read-only relocations',
'err_msg' => 'no read-only relocations (libfko)',
'function' => \&read_only_relocations,
'binary' => $libfko_bin,
'fatal' => $NO
},
{
'category' => 'build security',
'subcategory' => 'libfko',
'detail' => 'immediate binding',
'err_msg' => 'no immediate binding (libfko)',
'function' => \&immediate_binding,
'binary' => $libfko_bin,
'fatal' => $NO
},
{
'category' => 'preliminaries',
'subcategory' => 'client',
'detail' => 'usage info',
'err_msg' => 'could not get usage info',
'function' => \&generic_exec,
'cmdline' => "LD_LIBRARY_PATH=$lib_dir $valgrind_str $fwknopCmd -h",
'fatal' => $NO
},
{
'category' => 'preliminaries',
'subcategory' => 'client',
'detail' => 'getopt() no such argument',
'err_msg' => 'getopt() allowed non-existant argument',
'function' => \&generic_exec,
'cmdline' => "LD_LIBRARY_PATH=$lib_dir $valgrind_str $fwknopCmd --no-such-arg",
'exec_err' => $YES,
'fatal' => $NO
},
{
'category' => 'preliminaries',
'subcategory' => 'client',
'detail' => '--test mode, packet not sent',
'err_msg' => '--test mode, packet sent?',
'function' => \&generic_exec,
'positive_output_matches' => [qr/test\smode\senabled/],
'cmdline' => "$default_client_args --test",
'fatal' => $NO
},
{
'category' => 'preliminaries',
'subcategory' => 'client',
'detail' => 'expected code version',
'err_msg' => 'code version mis-match',
'function' => \&expected_code_version,
'cmdline' => "LD_LIBRARY_PATH=$lib_dir $valgrind_str $fwknopCmd --version",
'fatal' => $NO
},
{
'category' => 'preliminaries',
'subcategory' => 'server',
'detail' => 'usage info',
'err_msg' => 'could not get usage info',
'function' => \&generic_exec,
'cmdline' => "LD_LIBRARY_PATH=$lib_dir $valgrind_str $fwknopdCmd -h",
'fatal' => $NO
},
{
'category' => 'preliminaries',
'subcategory' => 'server',
'detail' => 'getopt() no such argument',
'err_msg' => 'getopt() allowed non-existant argument',
'function' => \&generic_exec,
'cmdline' => "LD_LIBRARY_PATH=$lib_dir $valgrind_str $fwknopdCmd --no-such-arg",
'exec_err' => $YES,
'fatal' => $NO
},
{
'category' => 'preliminaries',
'subcategory' => 'server',
'detail' => 'expected code version',
'err_msg' => 'code version mis-match',
'function' => \&expected_code_version,
'cmdline' => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
"$fwknopdCmd -c $cf{'def'} -a " .
"$cf{'def_access'} --version",
'fatal' => $NO
},
{
'category' => 'preliminaries',
'detail' => 'collecting system specifics',
'err_msg' => 'could not get complete system specs',
'function' => \&specs,
'binary' => $fwknopdCmd,
'fatal' => $NO
},
{
'category' => 'basic operations',
'detail' => 'dump config',
'err_msg' => 'could not dump configuration',
'function' => \&generic_exec,
'positive_output_matches' => [qr/SYSLOG_IDENTITY/],
'exec_err' => $NO,
'cmdline' => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
"$fwknopdCmd -c $cf{'def'} " .
"-a $cf{'def_access'} --dump-config",
'fatal' => $NO
},
{
'category' => 'basic operations',
'detail' => 'override config',
'err_msg' => 'could not override configuration',
'function' => \&generic_exec,
'positive_output_matches' => [qr/ENABLE_PCAP_PROMISC.*\'Y\'/],
'exec_err' => $NO,
'cmdline' => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
"$fwknopdCmd $default_server_conf_args " .
"-O $conf_dir/override_fwknopd.conf --dump-config",
'fatal' => $NO
},
{
'category' => 'basic operations',
'subcategory' => 'client',
'detail' => '--get-key path validation',
'err_msg' => 'accepted improper --get-key path',
'function' => \&generic_exec,
'positive_output_matches' => [qr/could\snot\sopen/i],
'exec_err' => $YES,
'cmdline' => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
"$fwknopCmd -A tcp/22 -s $fake_ip " .
"-D $loopback_ip --get-key not/there",
'fatal' => $YES
},
{
'category' => 'basic operations',
'subcategory' => 'client',
'detail' => 'require [-s|-R|-a]',
'err_msg' => 'allowed null allow IP',
'function' => \&generic_exec,
'positive_output_matches' => [qr/must\suse\sone\sof/i],
'exec_err' => $YES,
'cmdline' => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
"$fwknopCmd -D $loopback_ip",
'fatal' => $NO
},
{
'category' => 'basic operations',
'subcategory' => 'client',
'detail' => '--allow-ip <IP> valid IP',
'err_msg' => 'permitted invalid --allow-ip arg',
'function' => \&generic_exec,
'positive_output_matches' => [qr/Invalid\sallow\sIP\saddress/i],
'exec_err' => $YES,
'cmdline' => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
"$fwknopCmd -A tcp/22 -a invalidIP -D $loopback_ip",
'fatal' => $NO
},
{
'category' => 'basic operations',
'subcategory' => 'client',
'detail' => '-A <proto>/<port> specification (proto)',
'err_msg' => 'permitted invalid -A <proto>/<port>',
'function' => \&generic_exec,
'positive_output_matches' => [qr/Invalid\sSPA\saccess\smessage/i],
'exec_err' => $YES,
'cmdline' => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
"$fwknopCmd -A invalid/22 -a $fake_ip -D $loopback_ip",
'fatal' => $NO
},
{
'category' => 'basic operations',
'subcategory' => 'client',
'detail' => '-A <proto>/<port> specification (port)',
'err_msg' => 'permitted invalid -A <proto>/<port>',
'function' => \&generic_exec,
'positive_output_matches' => [qr/Invalid\sSPA\saccess\smessage/i],
'exec_err' => $YES,
'cmdline' => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
"$fwknopCmd -A tcp/600001 -a $fake_ip -D $loopback_ip",
'fatal' => $NO
},
{
'category' => 'basic operations',
'subcategory' => 'client',
'detail' => 'generate SPA packet',
'err_msg' => 'could not generate SPA packet',
'function' => \&client_send_spa_packet,
'cmdline' => $default_client_args,
'fatal' => $YES
},
{
'category' => 'basic operations',
'subcategory' => 'server',
'detail' => 'list current fwknopd fw rules',
'err_msg' => 'could not list current fwknopd fw rules',
'function' => \&generic_exec,
'cmdline' => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
"$fwknopdCmd $default_server_conf_args --fw-list",
'fatal' => $NO
},
{
'category' => 'basic operations',
'subcategory' => 'server',
'detail' => 'list all current fw rules',
'err_msg' => 'could not list all current fw rules',
'function' => \&generic_exec,
'cmdline' => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
"$fwknopdCmd $default_server_conf_args --fw-list-all",
'fatal' => $NO
},
{
'category' => 'basic operations',
'subcategory' => 'server',
'detail' => 'flush current firewall rules',
'err_msg' => 'could not flush current fw rules',
'function' => \&generic_exec,
'cmdline' => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
"$fwknopdCmd $default_server_conf_args --fw-flush",
'fatal' => $NO
},
{
'category' => 'basic operations',
'subcategory' => 'server',
'detail' => 'start',
'err_msg' => 'start error',
'function' => \&server_start,
'fwknopd_cmdline' => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
"$fwknopdCmd $default_server_conf_args $intf_str",
'fatal' => $NO
},
{
'category' => 'basic operations',
'subcategory' => 'server',
'detail' => 'stop',
'err_msg' => 'stop error',
'function' => \&server_stop,
'fwknopd_cmdline' => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
"$fwknopdCmd $default_server_conf_args $intf_str",
'fatal' => $NO
},
{
'category' => 'basic operations',
'subcategory' => 'server',
'detail' => 'write PID',
'err_msg' => 'did not write PID',
'function' => \&write_pid,
'fwknopd_cmdline' => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
"$fwknopdCmd $default_server_conf_args $intf_str",
'fatal' => $NO
},
{
'category' => 'basic operations',
'subcategory' => 'server',
'detail' => '--packet-limit 1 exit',
'err_msg' => 'did not exit after one packet',
'function' => \&server_packet_limit,
'fwknopd_cmdline' => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
"$fwknopdCmd $default_server_conf_args --packet-limit 1 $intf_str",
'fatal' => $NO
},
{
'category' => 'basic operations',
'subcategory' => 'server',
'detail' => 'ignore packets < min SPA len (140)',
'err_msg' => 'did not ignore small packets',
'function' => \&server_ignore_small_packets,
'fwknopd_cmdline' => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
"$fwknopdCmd $default_server_conf_args --packet-limit 1 $intf_str",
'fatal' => $NO
},
{
'category' => 'basic operations',
'subcategory' => 'server',
'detail' => '-P bpf filter ignore packet',
'err_msg' => 'filter did not ignore packet',
'function' => \&server_bpf_ignore_packet,
'cmdline' => $default_client_args,
'fwknopd_cmdline' => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
"$fwknopdCmd $default_server_conf_args --packet-limit 1 $intf_str " .
qq|-P "udp port $non_std_spa_port"|,
'fatal' => $NO
},
{
'category' => 'Rijndael SPA',
'subcategory' => 'client+server',
'detail' => 'complete cycle (tcp/22 ssh)',
'err_msg' => 'could not complete SPA cycle',
'function' => \&spa_cycle,
'cmdline' => $default_client_args,
'fwknopd_cmdline' => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
"$fwknopdCmd $default_server_conf_args $intf_str",
'fw_rule_created' => $NEW_RULE_REQUIRED,
'fw_rule_removed' => $NEW_RULE_REMOVED,
'fatal' => $NO
},
{
'category' => 'Rijndael SPA',
'subcategory' => 'client+server',
'detail' => 'permissions check cycle (tcp/22)',
'err_msg' => 'could not complete SPA cycle',
'function' => \&permissions_check,
'cmdline' => $default_client_args,
'fwknopd_cmdline' => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
"$fwknopdCmd $default_server_conf_args $intf_str",
'server_positive_output_matches' => [qr/permissions\sshould\sonly\sbe\suser/],
'fw_rule_created' => $NEW_RULE_REQUIRED,
'fw_rule_removed' => $NEW_RULE_REMOVED,
'fatal' => $NO
},
{
'category' => 'Rijndael SPA',
'subcategory' => 'client+server',
'detail' => 'client IP resolve (tcp/22 ssh)',
'err_msg' => 'could not complete SPA cycle',
'function' => \&spa_cycle,
'cmdline' => $client_ip_resolve_args,
'no_ip_check' => 1,
'fwknopd_cmdline' => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
"$fwknopdCmd $default_server_conf_args $intf_str",
'fw_rule_created' => $NEW_RULE_REQUIRED,
'fw_rule_removed' => $NEW_RULE_REMOVED,
'fatal' => $NO
},
{
'category' => 'Rijndael SPA',
'subcategory' => 'client+server',
'detail' => 'dual usage access key (tcp/80 http)',
'err_msg' => 'could not complete SPA cycle',
'function' => \&spa_cycle,
'cmdline' => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
"$fwknopCmd -A tcp/80 -a $fake_ip -D $loopback_ip --get-key " .
"$local_key_file --verbose --verbose",
'fwknopd_cmdline' => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
"$fwknopdCmd -c $cf{'def'} -a $cf{'dual_key_access'} " .
"-d $default_digest_file -p $default_pid_file $intf_str",
### check for the first stanza that does not allow tcp/80 - the
### second stanza allows this
'server_positive_output_matches' => [qr/stanza #1\)\sOne\sor\smore\srequested\sprotocol\/ports\swas\sdenied/],
'fw_rule_created' => $NEW_RULE_REQUIRED,
'fw_rule_removed' => $NEW_RULE_REMOVED,
'fatal' => $NO
},
{
'category' => 'Rijndael SPA',
'subcategory' => 'client+server',
'detail' => 'packet aging (past) (tcp/22 ssh)',
'err_msg' => 'old SPA packet accepted',
'function' => \&spa_cycle,
'cmdline' => "$default_client_args --time-offset-minus 300s",
'fwknopd_cmdline' => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
"$fwknopdCmd $default_server_conf_args $intf_str",
'server_positive_output_matches' => [qr/SPA\sdata\stime\sdifference/],
'fw_rule_created' => $REQUIRE_NO_NEW_RULE,
'fatal' => $NO
},
{
'category' => 'Rijndael SPA',
'subcategory' => 'client+server',
'detail' => 'packet aging (future) (tcp/22 ssh)',
'err_msg' => 'future SPA packet accepted',
'function' => \&spa_cycle,
'cmdline' => "$default_client_args --time-offset-plus 300s",
'fwknopd_cmdline' => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
"$fwknopdCmd $default_server_conf_args $intf_str",
'server_positive_output_matches' => [qr/SPA\sdata\stime\sdifference/],
'fw_rule_created' => $REQUIRE_NO_NEW_RULE,
'fatal' => $NO
},
{
'category' => 'Rijndael SPA',
'subcategory' => 'client+server',
'detail' => 'expired stanza (tcp/22 ssh)',
'err_msg' => 'SPA packet accepted',
'function' => \&spa_cycle,
'cmdline' => $default_client_args,
'fwknopd_cmdline' => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
"$fwknopdCmd -c $cf{'def'} -a $cf{'exp_access'} " .
"-d $default_digest_file -p $default_pid_file $intf_str",
'server_positive_output_matches' => [qr/Access\sstanza\shas\sexpired/],
'fw_rule_created' => $REQUIRE_NO_NEW_RULE,
'fatal' => $NO
},
{
'category' => 'Rijndael SPA',
'subcategory' => 'client+server',
'detail' => 'invalid expire date (tcp/22 ssh)',
'err_msg' => 'SPA packet accepted',
'function' => \&spa_cycle,
'cmdline' => $default_client_args,
'fwknopd_cmdline' => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
"$fwknopdCmd -c $cf{'def'} -a $cf{'invalid_exp_access'} " .
"-d $default_digest_file -p $default_pid_file $intf_str",
'server_positive_output_matches' => [qr/invalid\sdate\svalue/],
'fw_rule_created' => $REQUIRE_NO_NEW_RULE,
'fatal' => $NO
},
{
'category' => 'Rijndael SPA',
'subcategory' => 'client+server',
'detail' => 'expired epoch stanza (tcp/22 ssh)',
'err_msg' => 'SPA packet accepted',
'function' => \&spa_cycle,
'cmdline' => $default_client_args,
'fwknopd_cmdline' => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
"$fwknopdCmd -c $cf{'def'} -a $cf{'exp_epoch_access'} " .
"-d $default_digest_file -p $default_pid_file $intf_str",
'server_positive_output_matches' => [qr/Access\sstanza\shas\sexpired/],
'fw_rule_created' => $REQUIRE_NO_NEW_RULE,
'fatal' => $NO
},
{
'category' => 'Rijndael SPA',
'subcategory' => 'client+server',
'detail' => 'future expired stanza (tcp/22 ssh)',
'err_msg' => 'SPA packet not accepted',
'function' => \&spa_cycle,
'cmdline' => $default_client_args,
'fwknopd_cmdline' => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
"$fwknopdCmd -c $cf{'def'} -a $cf{'future_exp_access'} " .
"-d $default_digest_file -p $default_pid_file $intf_str",
'fw_rule_created' => $NEW_RULE_REQUIRED,
'fw_rule_removed' => $NEW_RULE_REMOVED,
'fatal' => $NO
},
{
'category' => 'Rijndael SPA',
'subcategory' => 'client+server',
'detail' => 'OPEN_PORTS (tcp/22 ssh)',
'err_msg' => "improper OPEN_PORTS result",
'function' => \&spa_cycle,
'cmdline' => $default_client_args,
'fwknopd_cmdline' => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
"$fwknopdCmd -c $cf{'def'} -a $cf{'open_ports_access'} " .
"-d $default_digest_file -p $default_pid_file $intf_str",
'fw_rule_created' => $NEW_RULE_REQUIRED,
'fw_rule_removed' => $NEW_RULE_REMOVED,
'fatal' => $NO
},
{
'category' => 'Rijndael SPA',
'subcategory' => 'client+server',
'detail' => 'OPEN_PORTS mismatch',
'err_msg' => "SPA packet accepted",
'function' => \&spa_cycle,
'cmdline' => $default_client_args,
'fwknopd_cmdline' => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
"$fwknopdCmd -c $cf{'def'} -a $cf{'open_ports_mismatch'} " .
"-d $default_digest_file -p $default_pid_file $intf_str",
'server_positive_output_matches' => [qr/One\s+or\s+more\s+requested/],
'fw_rule_created' => $REQUIRE_NO_NEW_RULE,
'fatal' => $NO
},
### spoof the source IP on the SPA packet
{
'category' => 'Rijndael SPA',
'subcategory' => 'client+server',
'detail' => "udpraw spoof src IP (tcp/22 ssh)",
'err_msg' => "could not spoof source IP",
'function' => \&spa_cycle,
'cmdline' => "$default_client_args -P udpraw -Q $spoof_ip",
'fwknopd_cmdline' => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
"$fwknopdCmd $default_server_conf_args $intf_str",
'fw_rule_created' => $NEW_RULE_REQUIRED,
'fw_rule_removed' => $NEW_RULE_REMOVED,
'server_positive_output_matches' => [qr/SPA\sPacket\sfrom\sIP\:\s$spoof_ip\s/],
'fatal' => $NO
},
{
'category' => 'Rijndael SPA',
'subcategory' => 'client+server',
'detail' => "tcpraw spoof src IP (tcp/22 ssh)",
'err_msg' => "could not spoof source IP",
'function' => \&spa_cycle,
'cmdline' => "$default_client_args -P tcpraw -Q $spoof_ip",
'fwknopd_cmdline' => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
"$fwknopdCmd -c $cf{'tcp_pcap_filter'} -a $cf{'def_access'} " .
"-d $default_digest_file -p $default_pid_file $intf_str",
'fw_rule_created' => $NEW_RULE_REQUIRED,
'fw_rule_removed' => $NEW_RULE_REMOVED,
'server_positive_output_matches' => [qr/SPA\sPacket\sfrom\sIP\:\s$spoof_ip\s/],
'fatal' => $NO
},
{
'category' => 'Rijndael SPA',
'subcategory' => 'client+server',
'detail' => "icmp spoof src IP (tcp/22 ssh)",
'err_msg' => "could not spoof source IP",
'function' => \&spa_cycle,
'cmdline' => "$default_client_args -P icmp -Q $spoof_ip",
'fwknopd_cmdline' => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
"$fwknopdCmd -c $cf{'icmp_pcap_filter'} -a $cf{'def_access'} " .
"-d $default_digest_file -p $default_pid_file $intf_str",
'fw_rule_created' => $NEW_RULE_REQUIRED,
'fw_rule_removed' => $NEW_RULE_REMOVED,
'server_positive_output_matches' => [qr/SPA\sPacket\sfrom\sIP\:\s$spoof_ip\s/],
'fatal' => $NO
},
{
'category' => 'Rijndael SPA',
'subcategory' => 'client+server',
'detail' => "icmp type/code 8/0 spoof src IP ",
'err_msg' => "could not spoof source IP",
'function' => \&spa_cycle,
'cmdline' => "$default_client_args -P icmp --icmp-type 8 --icmp-code 0 -Q $spoof_ip",
'fwknopd_cmdline' => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
"$fwknopdCmd -c $cf{'icmp_pcap_filter'} -a $cf{'def_access'} " .
"-d $default_digest_file -p $default_pid_file $intf_str",
'fw_rule_created' => $NEW_RULE_REQUIRED,
'fw_rule_removed' => $NEW_RULE_REMOVED,
'server_positive_output_matches' => [qr/SPA\sPacket\sfrom\sIP\:\s$spoof_ip\s/],
'fatal' => $NO
},
### SPA over TCP (not really "single" packet auth since a TCP connection
### is established)
{
'category' => 'Rijndael SPA',
'subcategory' => 'client+server',
'detail' => "SPA over TCP connection",
'err_msg' => "could not send/process SPA packet over TCP connection",
'function' => \&spa_cycle,
'cmdline' => "$default_client_args -P tcp",
'fwknopd_cmdline' => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
"$fwknopdCmd -c $cf{'tcp_server'} -a $cf{'def_access'} " .
"-d $default_digest_file -p $default_pid_file $intf_str",
'fw_rule_created' => $NEW_RULE_REQUIRED,
'fw_rule_removed' => $NEW_RULE_REMOVED,
'fatal' => $NO
},
{
'category' => 'Rijndael SPA',
'subcategory' => 'client+server',
'detail' => 'require user (tcp/22 ssh)',
'err_msg' => "missed require user criteria",
'function' => \&spa_cycle,
'cmdline' => "SPOOF_USER=$spoof_user $default_client_args",
'fwknopd_cmdline' => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
"$fwknopdCmd -c $cf{'def'} -a $cf{'require_user_access'} " .
"-d $default_digest_file -p $default_pid_file $intf_str",
'fw_rule_created' => $NEW_RULE_REQUIRED,
'fw_rule_removed' => $NEW_RULE_REMOVED,
'fatal' => $NO
},
{
'category' => 'Rijndael SPA',
'subcategory' => 'client+server',
'detail' => 'user mismatch (tcp/22 ssh)',
'err_msg' => "improper user accepted for access",
'function' => \&user_mismatch,
'function' => \&spa_cycle,
'cmdline' => $default_client_args,
'fwknopd_cmdline' => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
"$fwknopdCmd -c $cf{'def'} -a $cf{'user_mismatch_access'} " .
"-d $default_digest_file -p $default_pid_file $intf_str",
'server_positive_output_matches' => [qr/Username\s+in\s+SPA\s+data/],
'fw_rule_created' => $REQUIRE_NO_NEW_RULE,
'fatal' => $NO
},
{
'category' => 'Rijndael SPA',
'subcategory' => 'client+server',
'detail' => 'require src (tcp/22 ssh)',
'err_msg' => "fw rule not created",
'function' => \&spa_cycle,
'cmdline' => $default_client_args,
'fwknopd_cmdline' => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
"$fwknopdCmd -c $cf{'def'} -a $cf{'require_src_access'} " .
"-d $default_digest_file -p $default_pid_file $intf_str",
'fw_rule_created' => $NEW_RULE_REQUIRED,
'fw_rule_removed' => $NEW_RULE_REMOVED,
'fatal' => $NO
},
{
'category' => 'Rijndael SPA',
'subcategory' => 'client+server',
'detail' => 'mismatch require src (tcp/22 ssh)',
'err_msg' => "fw rule created",
'function' => \&spa_cycle,
'cmdline' => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
"$fwknopCmd -A tcp/22 -s -D $loopback_ip --get-key " .
"$local_key_file --verbose --verbose",
'fwknopd_cmdline' => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
"$fwknopdCmd -c $cf{'def'} -a $cf{'require_src_access'} " .
"-d $default_digest_file -p $default_pid_file $intf_str",
'server_positive_output_matches' => [qr/Got\s0.0.0.0\swhen\svalid\ssource\sIP/],
'fw_rule_created' => $REQUIRE_NO_NEW_RULE,
'fatal' => $NO
},
{
'category' => 'Rijndael SPA',
'subcategory' => 'client+server',
'detail' => 'IP filtering (tcp/22 ssh)',
'err_msg' => "did not filter $loopback_ip",
'function' => \&spa_cycle,
'cmdline' => $default_client_args,
'fwknopd_cmdline' => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
"$fwknopdCmd -c $cf{'def'} -a $cf{'no_src_match'} " .
"-d $default_digest_file -p $default_pid_file $intf_str",
'server_positive_output_matches' => [qr/No\saccess\sdata\sfound/],
'fw_rule_created' => $REQUIRE_NO_NEW_RULE,
'fatal' => $NO
},
{
'category' => 'Rijndael SPA',
'subcategory' => 'client+server',
'detail' => 'subnet filtering (tcp/22 ssh)',
'err_msg' => "did not filter $loopback_ip",
'function' => \&spa_cycle,
'cmdline' => $default_client_args,
'fwknopd_cmdline' => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
"$fwknopdCmd -c $cf{'def'} -a $cf{'no_subnet_match'} " .
"-d $default_digest_file -p $default_pid_file $intf_str",
'server_positive_output_matches' => [qr/No\saccess\sdata\sfound/],
'fw_rule_created' => $REQUIRE_NO_NEW_RULE,
'fatal' => $NO
},
{
'category' => 'Rijndael SPA',
'subcategory' => 'client+server',
'detail' => 'IP+subnet filtering (tcp/22 ssh)',
'err_msg' => "did not filter $loopback_ip",
'function' => \&spa_cycle,
'cmdline' => $default_client_args,
'fwknopd_cmdline' => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
"$fwknopdCmd -c $cf{'def'} -a $cf{'no_multi_src'} " .
"-d $default_digest_file -p $default_pid_file $intf_str",
'server_positive_output_matches' => [qr/No\saccess\sdata\sfound/],
'fw_rule_created' => $REQUIRE_NO_NEW_RULE,
'fatal' => $NO
},
{
'category' => 'Rijndael SPA',
'subcategory' => 'client+server',
'detail' => 'IP match (tcp/22 ssh)',
'err_msg' => "did not filter $loopback_ip",
'function' => \&spa_cycle,
'cmdline' => $default_client_args,
'fwknopd_cmdline' => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
"$fwknopdCmd -c $cf{'def'} -a $cf{'ip_src_match'} " .
"-d $default_digest_file -p $default_pid_file $intf_str",
'fw_rule_created' => $NEW_RULE_REQUIRED,
'fw_rule_removed' => $NEW_RULE_REMOVED,
'fatal' => $NO
},
{
'category' => 'Rijndael SPA',
'subcategory' => 'client+server',
'detail' => 'subnet match (tcp/22 ssh)',
'err_msg' => "did not filter $loopback_ip",
'function' => \&spa_cycle,
'cmdline' => $default_client_args,
'fwknopd_cmdline' => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
"$fwknopdCmd -c $cf{'def'} -a $cf{'subnet_src_match'} " .
"-d $default_digest_file -p $default_pid_file $intf_str",
'fw_rule_created' => $NEW_RULE_REQUIRED,
'fw_rule_removed' => $NEW_RULE_REMOVED,
'fatal' => $NO
},
{
'category' => 'Rijndael SPA',
'subcategory' => 'client+server',
'detail' => 'multi IP/net match (tcp/22 ssh)',
'err_msg' => "did not filter $loopback_ip",
'function' => \&spa_cycle,
'cmdline' => $default_client_args,
'fwknopd_cmdline' => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
"$fwknopdCmd -c $cf{'def'} -a $cf{'multi_src_access'} " .
"-d $default_digest_file -p $default_pid_file $intf_str",
'fw_rule_created' => $NEW_RULE_REQUIRED,
'fw_rule_removed' => $NEW_RULE_REMOVED,
'fatal' => $NO
},
{
'category' => 'Rijndael SPA',
'subcategory' => 'client+server',
'detail' => 'multi access stanzas (tcp/22 ssh)',
'err_msg' => "could not complete SPA cycle",
'function' => \&spa_cycle,
'cmdline' => $default_client_args,
'fwknopd_cmdline' => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
"$fwknopdCmd -c $cf{'def'} -a $cf{'multi_stanza_access'} " .
"-d $default_digest_file -p $default_pid_file $intf_str",
'fw_rule_created' => $NEW_RULE_REQUIRED,
'fw_rule_removed' => $NEW_RULE_REMOVED,
'fatal' => $NO
},
{
'category' => 'Rijndael SPA',
'subcategory' => 'client+server',
'detail' => 'bad/good key stanzas (tcp/22 ssh)',
'err_msg' => "could not complete SPA cycle",
'function' => \&spa_cycle,
'cmdline' => $default_client_args,
'fwknopd_cmdline' => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
"$fwknopdCmd -c $cf{'def'} -a $cf{'broken_keys_access'} " .
"-d $default_digest_file -p $default_pid_file $intf_str",
'fw_rule_created' => $NEW_RULE_REQUIRED,
'fw_rule_removed' => $NEW_RULE_REMOVED,
'fatal' => $NO
},
{
'category' => 'Rijndael SPA',
'subcategory' => 'client+server',
'detail' => "non-enabled NAT (tcp/22 ssh)",
'err_msg' => "SPA packet not filtered",
'function' => \&spa_cycle,
'cmdline' => "$default_client_args -N $internal_nat_host:22",
'fwknopd_cmdline' => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
"$fwknopdCmd $default_server_conf_args $intf_str",
'server_positive_output_matches' => [qr/requested\sNAT\saccess.*not\senabled/i],
'server_conf' => $cf{'nat'},
'fw_rule_created' => $REQUIRE_NO_NEW_RULE,
'fatal' => $NO
},
{
'category' => 'Rijndael SPA',
'subcategory' => 'client+server',
'detail' => "NAT to $internal_nat_host (tcp/22 ssh)",
'err_msg' => "could not complete NAT SPA cycle",
'function' => \&spa_cycle,
'cmdline' => "$default_client_args -N $internal_nat_host:22",
'fwknopd_cmdline' => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
"$fwknopdCmd -c $cf{'nat'} -a $cf{'open_ports_access'} " .
"-d $default_digest_file -p $default_pid_file $intf_str",
'server_positive_output_matches' => [qr/to\:$internal_nat_host\:22/i],
'fw_rule_created' => $NEW_RULE_REQUIRED,
'fw_rule_removed' => $NEW_RULE_REMOVED,
'server_conf' => $cf{'nat'},
'fatal' => $NO
},
{
'category' => 'Rijndael SPA',
'subcategory' => 'client+server',
'detail' => "force NAT $force_nat_host (tcp/22 ssh)",
'err_msg' => "could not complete NAT SPA cycle",
'function' => \&spa_cycle,
'cmdline' => $default_client_args,
'fwknopd_cmdline' => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
"$fwknopdCmd -c $cf{'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_negative_output_matches' => [qr/to\:$internal_nat_host\:22/i],
'fw_rule_created' => $NEW_RULE_REQUIRED,
'fw_rule_removed' => $NEW_RULE_REMOVED,
'server_conf' => $cf{'nat'},
'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 $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,
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' => $cf{'nat'},
'fatal' => $NO
},
{
'category' => 'Rijndael SPA',
'subcategory' => 'client+server',
'detail' => "local NAT non-FORCE_NAT (tcp/22 ssh)",
'err_msg' => "could not complete NAT SPA cycle",
'function' => \&spa_cycle,
'cmdline' => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
"$fwknopCmd -A tcp/80 -a $fake_ip -D $loopback_ip --get-key " .
"$local_key_file --verbose --verbose --nat-local --nat-port 22",
'fwknopd_cmdline' => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
"$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,
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' => $cf{'nat'},
'fatal' => $NO
},
{
'category' => 'Rijndael SPA',
'subcategory' => 'client+server',
'detail' => 'complete cycle (tcp/23 telnet)',
'err_msg' => 'could not complete SPA cycle',
'function' => \&spa_cycle,
'cmdline' => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
"$fwknopCmd -A tcp/23 -a $fake_ip -D $loopback_ip --get-key " .
"$local_key_file --verbose --verbose",
'fwknopd_cmdline' => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
"$fwknopdCmd $default_server_conf_args $intf_str",
'fw_rule_created' => $NEW_RULE_REQUIRED,
'fw_rule_removed' => $NEW_RULE_REMOVED,
'fatal' => $NO
},
{
'category' => 'Rijndael SPA',
'subcategory' => 'client+server',
'detail' => 'complete cycle (tcp/9418 git)',
'err_msg' => 'could not complete SPA cycle',
'function' => \&spa_cycle,
'cmdline' => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
"$fwknopCmd -A tcp/9418 -a $fake_ip -D $loopback_ip --get-key " .
"$local_key_file --verbose --verbose",
'fwknopd_cmdline' => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
"$fwknopdCmd $default_server_conf_args $intf_str",
'fw_rule_created' => $NEW_RULE_REQUIRED,
'fw_rule_removed' => $NEW_RULE_REMOVED,
'fatal' => $NO
},
{
'category' => 'Rijndael SPA',
'subcategory' => 'client+server',
'detail' => 'complete cycle (tcp/60001)',
'err_msg' => 'could not complete SPA cycle',
'function' => \&spa_cycle,
'cmdline' => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
"$fwknopCmd -A tcp/60001 -a $fake_ip -D $loopback_ip --get-key " .
"$local_key_file --verbose --verbose",
'fwknopd_cmdline' => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
"$fwknopdCmd $default_server_conf_args $intf_str",
'fw_rule_created' => $NEW_RULE_REQUIRED,
'fw_rule_removed' => $NEW_RULE_REMOVED,
'fatal' => $NO
},
{
'category' => 'Rijndael SPA',
'subcategory' => 'client+server',
'detail' => 'multi port (tcp/60001,udp/60001)',
'err_msg' => 'could not complete SPA cycle',
'function' => \&spa_cycle,
'cmdline' => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
"$fwknopCmd -A tcp/60001,udp/60001 -a $fake_ip -D $loopback_ip --get-key " .
"$local_key_file --verbose --verbose",
'fwknopd_cmdline' => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
"$fwknopdCmd $default_server_conf_args $intf_str",
'fw_rule_created' => $NEW_RULE_REQUIRED,
'fw_rule_removed' => $NEW_RULE_REMOVED,
'fatal' => $NO
},
{
'category' => 'Rijndael SPA',
'subcategory' => 'client+server',
'detail' => 'multi port (tcp/22,udp/53,tcp/1234)',
'err_msg' => 'could not complete SPA cycle',
'function' => \&spa_cycle,
'cmdline' => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
"$fwknopCmd -A tcp/22,udp/53,tcp/1234 -a $fake_ip -D $loopback_ip --get-key " .
"$local_key_file --verbose --verbose",
'fwknopd_cmdline' => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
"$fwknopdCmd $default_server_conf_args $intf_str",
'fw_rule_created' => $NEW_RULE_REQUIRED,
'fw_rule_removed' => $NEW_RULE_REMOVED,
'fatal' => $NO
},
{
'category' => 'Rijndael SPA',
'subcategory' => 'client+server',
'detail' => 'complete cycle (udp/53 dns)',
'err_msg' => 'could not complete SPA cycle',
'function' => \&spa_cycle,
'cmdline' => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
"$fwknopCmd -A udp/53 -a $fake_ip -D $loopback_ip --get-key " .
"$local_key_file --verbose --verbose",
'fwknopd_cmdline' => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
"$fwknopdCmd $default_server_conf_args $intf_str",
'fw_rule_created' => $NEW_RULE_REQUIRED,
'fw_rule_removed' => $NEW_RULE_REMOVED,
'fatal' => $NO
},
{
'category' => 'Rijndael SPA',
'subcategory' => 'client+server',
'detail' => "-P bpf SPA over port $non_std_spa_port",
'err_msg' => 'could not complete SPA cycle',
'function' => \&spa_cycle,
'cmdline' => "$default_client_args --server-port $non_std_spa_port",
'fwknopd_cmdline' => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
"$fwknopdCmd $default_server_conf_args $intf_str " .
qq|-P "udp port $non_std_spa_port"|,
'server_positive_output_matches' => [qr/PCAP\sfilter.*\s$non_std_spa_port/],
'fw_rule_created' => $NEW_RULE_REQUIRED,
'fw_rule_removed' => $NEW_RULE_REMOVED,
'fatal' => $NO
},
{
'category' => 'Rijndael SPA',
'subcategory' => 'client+server',
'detail' => 'random SPA port (tcp/22 ssh)',
'err_msg' => 'could not complete SPA cycle',
'function' => \&spa_cycle,
'cmdline' => "$default_client_args -r",
'fwknopd_cmdline' => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
"$fwknopdCmd $default_server_conf_args $intf_str " .
qq|-P "udp"|,
'fw_rule_created' => $NEW_RULE_REQUIRED,
'fw_rule_removed' => $NEW_RULE_REMOVED,
'fatal' => $NO
},
{
'category' => 'Rijndael SPA',
'subcategory' => 'client+server',
'detail' => 'spoof username (tcp/22)',
'err_msg' => 'could not spoof username',
'function' => \&spoof_username,
'cmdline' => "SPOOF_USER=$spoof_user LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
"$fwknopCmd -A tcp/22 -a $fake_ip -D $loopback_ip --get-key " .
"$local_key_file --verbose --verbose",
'fwknopd_cmdline' => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
"$fwknopdCmd $default_server_conf_args $intf_str",
'fatal' => $NO
},
{
'category' => 'Rijndael SPA',
'subcategory' => 'client+server',
'detail' => 'replay attack detection',
'err_msg' => 'could not detect replay attack',
'function' => \&replay_detection,
'cmdline' => $default_client_args,
'fwknopd_cmdline' => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
"$fwknopdCmd $default_server_conf_args $intf_str",
'replay_positive_output_matches' => [qr/Replay\sdetected\sfrom\ssource\sIP/],
'fatal' => $NO
},
{
'category' => 'Rijndael SPA',
'subcategory' => 'client+server',
'detail' => 'replay detection (Rijndael prefix)',
'err_msg' => 'could not detect replay attack',
'function' => \&replay_detection,
'pkt_prefix' => 'U2FsdGVkX1',
'cmdline' => $default_client_args,
'fwknopd_cmdline' => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
"$fwknopdCmd $default_server_conf_args $intf_str",
'replay_positive_output_matches' => [qr/Data\sis\snot\sa\svalid\sSPA\smessage\sformat/],
'fatal' => $NO
},
### fuzzing tests
{
'category' => 'Rijndael SPA',
'subcategory' => 'FUZZING',
'detail' => 'overly long port value',
'err_msg' => 'server crashed or did not detect error condition',
'function' => \&fuzzer,
### this packet was generated with a modified fwknop client via the
### following command line:
#
# LD_LIBRARY_PATH=../lib/.libs ../client/.libs/fwknop -A \
# "tcp/`perl -e '{print "1"x"40"}'`" -a 127.0.0.2 -D 127.0.0.1 \
# --get-key local_spa.key --verbose --verbose
#
# This problem was found by Fernando Arnaboldi of IOActive and exploits
# a buffer overflow in the fwknopd servers prior to 2.0.3 from
# authenticated clients.
#
'fuzzing_pkt' =>
'+JzxeTGlc6lwwzbJSrYChKx8bonWBIPajwGfEtGOaoglcMLbTY/GGXo/nxqiN1LykFS' .
'lDFXgrkyx2emJ7NGzYqQPUYZxLdZRocR9aRIptvXLLIPBcIpJASi/TUiJlw7CDFMcj0' .
'ptSBJJUZi0tozpKHETp3AgqfzyOy5FNs38aZsV5/sDl3Pt+kF7fTZJ+YLbmYY4yCUz2' .
'ZUYoCaJ7X78ULyJTi5eT7nug',
'server_positive_output_matches' => [qr/Args\scontain\sinvalid\sdata/],
'fwknopd_cmdline' => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
"$fwknopdCmd -c $cf{'disable_aging'} -a $cf{'def_access'} " .
"-d $default_digest_file -p $default_pid_file $intf_str",
'fatal' => $NO
},
{
'category' => 'Rijndael SPA',
'subcategory' => 'FUZZING',
'detail' => 'overly long proto value',
'err_msg' => 'server crashed or did not detect error condition',
'function' => \&fuzzer,
### this packet was generated with a modified fwknop client via the
### following command line:
#
# LD_LIBRARY_PATH=../lib/.libs ../client/.libs/fwknop -A \
# "tcp`perl -e '{print "A"x"28"}'`/1" -a 127.0.0.2 -D 127.0.0.1 \
# --get-key local_spa.key --verbose --verbose
#
# This problem was found by Fernando Arnaboldi of IOActive and exploits
# a buffer overflow in the fwknopd servers prior to 2.0.3 from
# authenticated clients.
#
'fuzzing_pkt' =>
'/im5MiJQmOdzqrdWXv+AjEtAm/HsLrdaTFcSw3ZskqpGOdDIrSCz3VXbFfv7qDkc5Y4' .
'q/k1mRXl9SGzpug87U5dZSyCdAr30z7/2kUFEPTGOQBi/x+L1t1pvdkm4xg13t09ldm' .
'5OD8KiV6qzqLOvN4ULJjvvJJWBZ9qvo/f2Q9Wf67g2KHiwS6EeCINAuMoUw/mNRQMa4' .
'oGnOXu3/DeWHJAwtSeh7EAr4',
'server_positive_output_matches' => [qr/Args\scontain\sinvalid\sdata/],
'fwknopd_cmdline' => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
"$fwknopdCmd -c $cf{'disable_aging'} -a $cf{'def_access'} " .
"-d $default_digest_file -p $default_pid_file $intf_str",
'fatal' => $NO
},
{
'category' => 'Rijndael SPA',
'subcategory' => 'FUZZING',
'detail' => 'overly long IP value',
'err_msg' => 'server crashed or did not detect error condition',
'function' => \&fuzzer,
### this packet was generated with a modified fwknop client via the
### following command line:
#
# LD_LIBRARY_PATH=../lib/.libs ../client/.libs/fwknop -A tcp/22 \
# -a `perl -e '{print "1"x"136"}'`.0.0.1 -D 127.0.0.1 \
# --get-key local_spa.key --verbose --verbose
#
# This problem was found by Fernando Arnaboldi of IOActive and exploits
# a condition in which pre-2.0.3 fwknopd servers fail to properly validate
# allow IP addresses from malicious authenticated clients.
#
'fuzzing_pkt' =>
'93f2rhsXLmBoPicWvYTqrbp+6lNqvWDc8dzmX2s3settwjBGRAXm33TB9agibEphrBu' .
'3d+7DEsivZLDS6Kz0JwdjX7t0J9c8es+DVNjlLnPtVNcxhs+2kUzimNrgysIXQRJ+GF' .
'GbhdxiXCqdy1vWxWpdoaZmY/CeGIkpoFJFPbJhCRLLX25UMvMF2wXj02MpI4d3t1/6W' .
'DM3taM3kZsiFv6HxFjAhIEuQ1oAg2OgRGXkDmT3jDNZMHUm0d4Ahm9LonG7RbOxq/B0' .
'qUvY8lkymbwvjelVok7Lvlc06cRhN4zm32D4V05g0vQS3PlX9C+mgph9DeAPVX+D8iZ' .
'8lGrxcPSfbCOW61k0MP+q1EhLZkc1qAm5g2+2cLNZcoBNEdh3yj8OTPZJyBVw',
'server_positive_output_matches' => [qr/Args\scontain\sinvalid\sdata/],
'fwknopd_cmdline' => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
"$fwknopdCmd -c $cf{'disable_aging'} -a $cf{'def_access'} " .
"-d $default_digest_file -p $default_pid_file $intf_str",
'fatal' => $NO
},
{
'category' => 'Rijndael SPA',
'subcategory' => 'FUZZING',
'detail' => 'negative port value',
'err_msg' => 'server crashed or did not detect error condition',
'function' => \&fuzzer,
### this packet was generated with a modified fwknop client via the
### following command line:
#
# LD_LIBRARY_PATH=../lib/.libs ../client/.libs/fwknop -A \
# tcp/-33 -a 127.0.0.2 -D 127.0.0.1 --get-key local_spa.key \
# --verbose --verbose
#
'fuzzing_pkt' =>
'/weoc+pEuQknZo8ImWTQBB+/PwSJ2/TcrmFoSkxpRXX4+jlUxoJakHrioxh8rhLmAD9' .
'8E4lMnq+EbM2XYdhs2alpZ5bovAFojMsYRWwr/BvRO4Um4Fmo9z9sY3DR477TXNYXBR' .
'iGXWxSL4u+AWSSePK3qiiYoRQVw',
'server_positive_output_matches' => [qr/Args\scontain\sinvalid\sdata/],
'fwknopd_cmdline' => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
"$fwknopdCmd -c $cf{'disable_aging'} -a $cf{'def_access'} " .
"-d $default_digest_file -p $default_pid_file $intf_str",
'fatal' => $NO
},
{
'category' => 'Rijndael SPA',
'subcategory' => 'FUZZING',
'detail' => 'null port value',
'err_msg' => 'server crashed or did not detect error condition',
'function' => \&fuzzer,
### this packet was generated with a modified fwknop client via the
### following command line:
#
# LD_LIBRARY_PATH=../lib/.libs ../client/.libs/fwknop -A tcp/ \
# -a 127.0.0.2 -D 127.0.0.1 --get-key local_spa.key \
# --verbose --verbose
#
'fuzzing_pkt' =>
'94nu7hvq6V/3A27GzjHwfPnPCQfs44ySlraIFYHOAqy5YqjkrBS67nH35tX55N1BrYZ' .
'07zvcT03keUhLE1Uo7Wme1nE7BfTOG5stmIK1UQI85sL52//lDHu+xCqNcL7GUKbVRz' .
'ekw+EUscVvUkrsRcVtSvOm+fCNo',
'server_positive_output_matches' => [qr/Args\scontain\sinvalid\sdata/],
'fwknopd_cmdline' => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
"$fwknopdCmd -c $cf{'disable_aging'} -a $cf{'def_access'} " .
"-d $default_digest_file -p $default_pid_file $intf_str",
'fatal' => $NO
},
{
'category' => 'Rijndael SPA',
'subcategory' => 'FUZZING',
'detail' => 'long FKO protocol value (enc mode trigger)',
'err_msg' => 'server crashed or did not detect error condition',
'function' => \&fuzzer,
### this packet was generated with a modified fwknop client via the
### following command line:
#
# LD_LIBRARY_PATH=../lib/.libs ../client/.libs/fwknop -A tcp/22 \
# -a 127.0.0.2 -D 127.0.0.1 --get-key local_spa.key --verbose --verbose
#
# This problem was found by Fernando Arnaboldi of IOActive and is designed
# to have fwknopd look for a mode decryption mode for a long Rijndael-
# encrypted SPA packet
#
'fuzzing_pkt' =>
'/ewH/k1XsDX+VQ8NlNvCZ4P2QOl/4IpJYXkq4TtAe3899OtApXJiTtPCuYW70XPuxge' .
'MtFjc4UfslK/r9v+FYfyd3fIIHCz0Q0M4+nM3agTLmJj8nOxk6ZeBj82SDQWhHAxGdJ' .
'IQALPve0ug4cuGxS3b4M+2Q/Av9i2tU3Lzlogw3sY0tk6wGf4zZk4UsviVXYpINniGT' .
'RhYSIQ1dfdkng7hKiHMDaObYY1GFp4nxEt/QjasAwvE+7/iFyoKN+IRpGG4v4hGEPh2' .
'vTDqmvfRuIHtgFD7NxZjt+m/jjcu0gkdWEoD4fenwGU35FlvchyM2AiAEw7yRzSABfn' .
'R9d3sYZGMtyASw2O1vSluwIxUUnDop3gxEIhJEj8h+01pA3K+klSpALeY9EZgHqYC7E' .
'ETuPS6dZ3764nWohtCY67JvNUX7TtNDNc2qrhrapdRP17+PT2Vh4s9m38V3WwVWC3uH' .
'X/klLZcHIt+aRDV+uekw9GOKSgwFL2ekPpr3gXxigc3zrxel5hcsqLOpVUa4CP/0HkG' .
'F0NPQvOT3ZvpeIJnirKP1ZX9gDFinqhuzL7oqktW61e1iwe7KZEdrZV0k2KZwyb8qU5' .
'rPAEnw',
'server_positive_output_matches' => [qr/No\sstanza\sencryption\smode\smatch/],
'fwknopd_cmdline' => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
"$fwknopdCmd -c $cf{'disable_aging'} -a $cf{'def_access'} " .
"-d $default_digest_file -p $default_pid_file $intf_str",
'fatal' => $NO
},
{
'category' => 'Rijndael SPA',
'subcategory' => 'FUZZING',
'detail' => 'long FKO protocol value (Rijndael trigger)',
'err_msg' => 'server crashed or did not detect error condition',
'function' => \&fuzzer,
### this packet was generated with a modified fwknop client via the
### following command line:
#
# LD_LIBRARY_PATH=../lib/.libs ../client/.libs/fwknop -A tcp/22 \
# -a 127.0.0.2 -D 127.0.0.1 --get-key local_spa.key --verbose --verbose
#
# This problem was found by Fernando Arnaboldi of IOActive and is designed
# to have fwknopd look for a mode decryption mode for a long Rijndael-
# encrypted SPA packet
#
'fuzzing_pkt' =>
'+YQNu4BFgiNeu8HeiBiNKriqCFSseALt9vJaKzkzK/OF4pjkJcvhGEOi7fEVXqn3VIdlGR' .
'DmBul2I7H3z18U9E97bWGgT9NexKgEPCuekL18ZEPf5xR3JleNsNWatqYgAOkgN8ZWE69Q' .
'qQUYYhxTvJHS6R+5JqFKB3A44hMXoICdYNkn9MAktHxk3PbbpQ+nA+jESwVCra2doAiLiM' .
'ucvGIZZiTv0Mc1blFYIE2zqZ/C7ct1V+ukwSkUv0r87eA7uJhmlpThRsL0dN6iekJ6i87B' .
'tE8QyuOXzOMftI11SUn/LwqD4RMdR21rvLrzR6ZB5eUX2UBpODyzX6n+PJJkTWCuFVT4z1' .
'MKY',
'server_positive_output_matches' => [qr/Args\scontain\sinvalid\sdata/],
'fwknopd_cmdline' => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
"$fwknopdCmd -c $cf{'disable_aging'} -a $cf{'def_access'} " .
"-d $default_digest_file -p $default_pid_file $intf_str",
'fatal' => $NO
},
{
'category' => 'Rijndael SPA',
'subcategory' => 'FUZZING',
'detail' => 'null proto value',
'err_msg' => 'server crashed or did not detect error condition',
'function' => \&fuzzer,
### this packet was generated with a modified fwknop client via the
### following command line:
#
# LD_LIBRARY_PATH=../lib/.libs ../client/.libs/fwknop -A /22 \
# -a 127.0.0.2 -D 127.0.0.1 --get-key local_spa.key \
# --verbose --verbose
#
'fuzzing_pkt' =>
'/JT14qxh9P4iy+CuUZahThaQjoEuL2zd46a+jL6sTrBZJSa6faUX4dH5fte/4ZJv+9f' .
'd/diWYKAUvdQ4DydPGlR7mwQa2W+obKpqrsTBz7D4054z6ATAOGpCtifakEVl1XRc2+' .
'hW04WpY8mdUNu9i+PrfPr7/KxqU',
'server_positive_output_matches' => [qr/Args\scontain\sinvalid\sdata/],
'fwknopd_cmdline' => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
"$fwknopdCmd -c $cf{'disable_aging'} -a $cf{'def_access'} " .
"-d $default_digest_file -p $default_pid_file $intf_str",
'fatal' => $NO
},
{
'category' => 'FUZZING',
'subcategory' => 'server',
'detail' => 'invalid SOURCE access.conf',
'err_msg' => 'server crashed or did not detect error condition',
'function' => \&generic_exec,
'cmdline' => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
"$fwknopdCmd -c $cf{'disable_aging'} -a $cf{'fuzz_source'} " .
"-d $default_digest_file -p $default_pid_file $intf_str",
'positive_output_matches' => [qr/Fatal\sinvalid/],
'exec_err' => $YES,
'fatal' => $NO
},
{
'category' => 'FUZZING',
'subcategory' => 'server',
'detail' => 'invalid OPEN_PORTS access.conf',
'err_msg' => 'server crashed or did not detect error condition',
'function' => \&generic_exec,
'cmdline' => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
"$fwknopdCmd -c $cf{'disable_aging'} -a $cf{'fuzz_open_ports'} " .
"-d $default_digest_file -p $default_pid_file $intf_str",
'positive_output_matches' => [qr/Fatal\sinvalid/],
'exec_err' => $YES,
'fatal' => $NO
},
{
'category' => 'FUZZING',
'subcategory' => 'server',
'detail' => 'invalid RESTRICT_PORTS access.conf',
'err_msg' => 'server crashed or did not detect error condition',
'function' => \&generic_exec,
'cmdline' => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
"$fwknopdCmd -c $cf{'disable_aging'} -a $cf{'fuzz_restrict_ports'} " .
"-d $default_digest_file -p $default_pid_file $intf_str",
'positive_output_matches' => [qr/Fatal\sinvalid/],
'exec_err' => $YES,
'fatal' => $NO
},
### command execution tests
{
'category' => 'Rijndael SPA',
'subcategory' => 'client+server',
'detail' => 'command execution',
'err_msg' => 'could not complete SPA cycle',
'function' => \&spa_cmd_exec_cycle,
'cmdline' => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
qq|$fwknopCmd --server-cmd "echo fwknoptest > $cmd_exec_test_file" | .
"-a $fake_ip -D $loopback_ip --get-key $local_key_file " .
"--verbose --verbose",
'fwknopd_cmdline' => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
"$fwknopdCmd -c $cf{'def'} -a $cf{'cmd_access'} " .
"-d $default_digest_file -p $default_pid_file $intf_str",
'fw_rule_created' => $REQUIRE_NO_NEW_RULE,
'fatal' => $NO
},
{
'category' => 'Rijndael SPA',
'subcategory' => 'server',
'detail' => 'digest cache structure',
'err_msg' => 'improper digest cache structure',
'function' => \&digest_cache_structure,
'fatal' => $NO
},
{
'category' => 'Rijndael SPA',
'subcategory' => 'server',
'detail' => 'ipfw active/expire sets not equal',
'err_msg' => 'allowed active/expire sets to be the same',
'function' => \&spa_cycle,
'cmdline' => $default_client_args,
'fwknopd_cmdline' => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
"$fwknopdCmd -c $cf{'ipfw_active_expire'} -a $cf{'def_access'} " .
"-d $default_digest_file -p $default_pid_file $intf_str",
'server_positive_output_matches' => [qr/Cannot\sset\sidentical\sipfw\sactive\sand\sexpire\ssets/],
'fw_rule_created' => $REQUIRE_NO_NEW_RULE,
'fatal' => $NO
},
{
'category' => 'Rijndael SPA',
'subcategory' => 'client+server',
'detail' => 'non-base64 altered SPA data',
'err_msg' => 'allowed improper SPA data',
'function' => \&altered_non_base64_spa_data,
'cmdline' => $default_client_args,
'fwknopd_cmdline' => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
"$fwknopdCmd $default_server_conf_args $intf_str",
'fatal' => $NO
},
{
'category' => 'Rijndael SPA',
'subcategory' => 'client+server',
'detail' => 'base64 altered SPA data',
'err_msg' => 'allowed improper SPA data',
'function' => \&altered_base64_spa_data,
'cmdline' => $default_client_args,
'fwknopd_cmdline' => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
"$fwknopdCmd $default_server_conf_args $intf_str",
'fatal' => $NO
},
{
'category' => 'Rijndael SPA',
'subcategory' => 'client+server',
'detail' => 'appended data to SPA pkt',
'err_msg' => 'allowed improper SPA data',
'function' => \&appended_spa_data,
'cmdline' => $default_client_args,
'fwknopd_cmdline' => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
"$fwknopdCmd $default_server_conf_args $intf_str",
'fatal' => $NO
},
{
'category' => 'Rijndael SPA',
'subcategory' => 'client+server',
'detail' => 'prepended data to SPA pkt',
'err_msg' => 'allowed improper SPA data',
'function' => \&prepended_spa_data,
'cmdline' => $default_client_args,
'fwknopd_cmdline' => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
"$fwknopdCmd $default_server_conf_args $intf_str",
'fatal' => $NO
},
### perl module checks
{
'category' => 'perl FKO module',
'subcategory' => 'compile/install',
'detail' => 'to: ./FKO',
'err_msg' => 'could not install FKO module',
'function' => \&perl_fko_module_compile_install,
'fatal' => $NO
},
{
'category' => 'perl FKO module',
'subcategory' => 'basic ops',
'detail' => 'create/destroy FKO object',
'err_msg' => 'could not create/destroy FKO object',
'function' => \&perl_fko_module_new_object,
'fatal' => $NO
},
{
'category' => 'perl FKO module',
'subcategory' => 'basic ops',
'detail' => 'create/destroy 1000 FKO objects',
'err_msg' => 'could not create/destroy FKO object',
'function' => \&perl_fko_module_new_objects_1000,
'fatal' => $NO
},
{
'category' => 'perl FKO module',
'subcategory' => 'basic ops',
'detail' => 'libfko version',
'err_msg' => 'could not get libfko version',
'function' => \&perl_fko_module_version,
'fatal' => $NO
},
{
'category' => 'perl FKO module',
'subcategory' => 'basic ops',
'detail' => 'libfko get random data',
'err_msg' => 'could not get libfko random data',
'function' => \&perl_fko_module_rand,
'fatal' => $NO
},
{
'category' => 'perl FKO module',
'subcategory' => 'basic ops',
'detail' => 'libfko get/set username',
'err_msg' => 'could not get libfko username',
'function' => \&perl_fko_module_user,
'fatal' => $NO
},
{
'category' => 'perl FKO module',
'subcategory' => 'basic ops',
'detail' => 'libfko timestamp',
'err_msg' => 'could not get libfko timestamp',
'function' => \&perl_fko_module_timestamp,
'fatal' => $NO
},
{
'category' => 'perl FKO module',
'subcategory' => 'basic ops',
'detail' => 'libfko get/set msg types',
'err_msg' => 'could not get/set libfko msg types',
'function' => \&perl_fko_module_msg_types,
'fatal' => $NO
},
{
'category' => 'perl FKO module',
'subcategory' => 'basic ops',
'detail' => 'libfko get/set msg',
'err_msg' => 'could not get/set libfko msg',
'function' => \&perl_fko_module_msg,
'fatal' => $NO
},
{
'category' => 'perl FKO module',
'subcategory' => 'compatibility',
'detail' => 'client FKO -> C server',
'err_msg' => 'invalid SPA packet data',
'function' => \&perl_fko_module_client_compatibility,
'fatal' => $NO
},
{
'category' => 'GPG (no pw) SPA',
'subcategory' => 'client+server',
'detail' => 'complete cycle (tcp/22 ssh)',
'err_msg' => 'could not complete SPA cycle',
'function' => \&spa_cycle,
'cmdline' => "$default_client_gpg_args_no_homedir "
. "--gpg-home-dir $gpg_client_home_dir_no_pw",
'fwknopd_cmdline' => $default_server_gpg_args_no_pw,
'fw_rule_created' => $NEW_RULE_REQUIRED,
'fw_rule_removed' => $NEW_RULE_REMOVED,
'fatal' => $NO
},
{
'category' => 'GPG (no pw) SPA',
'subcategory' => 'client+server',
'detail' => 'multi gpg-IDs (tcp/22 ssh)',
'err_msg' => 'could not complete SPA cycle',
'function' => \&spa_cycle,
'cmdline' => "$default_client_gpg_args_no_homedir "
. "--gpg-home-dir $gpg_client_home_dir_no_pw",
'fwknopd_cmdline' => "LD_LIBRARY_PATH=$lib_dir " .
"$valgrind_str $fwknopdCmd -c $cf{'def'} " .
"-a $cf{'multi_gpg_access'} $intf_str " .
"-d $default_digest_file -p $default_pid_file",
'fw_rule_created' => $NEW_RULE_REQUIRED,
'fw_rule_removed' => $NEW_RULE_REMOVED,
'fatal' => $NO
},
{
'category' => 'GPG (no pw) SPA',
'subcategory' => 'client+server',
'detail' => 'complete cycle (tcp/23 telnet)',
'err_msg' => 'could not complete SPA cycle',
'function' => \&spa_cycle,
'cmdline' => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
"$fwknopCmd -A tcp/23 -a $fake_ip -D $loopback_ip --get-key " .
"$local_key_file --verbose --verbose " .
"--gpg-recipient-key $gpg_server_key " .
"--gpg-signer-key $gpg_client_key " .
"--gpg-home-dir $gpg_client_home_dir_no_pw",
'fwknopd_cmdline' => $default_server_gpg_args_no_pw,
'fw_rule_created' => $NEW_RULE_REQUIRED,
'fw_rule_removed' => $NEW_RULE_REMOVED,
'fatal' => $NO
},
{
'category' => 'GPG (no pw) SPA',
'subcategory' => 'client+server',
'detail' => 'complete cycle (tcp/9418 git)',
'err_msg' => 'could not complete SPA cycle',
'function' => \&spa_cycle,
'cmdline' => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
"$fwknopCmd -A tcp/9418 -a $fake_ip -D $loopback_ip --get-key " .
"$local_key_file --verbose --verbose " .
"--gpg-recipient-key $gpg_server_key " .
"--gpg-signer-key $gpg_client_key " .
"--gpg-home-dir $gpg_client_home_dir_no_pw",
'fwknopd_cmdline' => $default_server_gpg_args_no_pw,
'fw_rule_created' => $NEW_RULE_REQUIRED,
'fw_rule_removed' => $NEW_RULE_REMOVED,
'fatal' => $NO
},
{
'category' => 'GPG (no pw) SPA',
'subcategory' => 'client+server',
'detail' => 'complete cycle (tcp/60001)',
'err_msg' => 'could not complete SPA cycle',
'function' => \&spa_cycle,
'cmdline' => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
"$fwknopCmd -A tcp/60001 -a $fake_ip -D $loopback_ip --get-key " .
"$local_key_file --verbose --verbose " .
"--gpg-recipient-key $gpg_server_key " .
"--gpg-signer-key $gpg_client_key " .
"--gpg-home-dir $gpg_client_home_dir_no_pw",
'fwknopd_cmdline' => $default_server_gpg_args_no_pw,
'fw_rule_created' => $NEW_RULE_REQUIRED,
'fw_rule_removed' => $NEW_RULE_REMOVED,
'fatal' => $NO
},
{
'category' => 'GPG (no pw) SPA',
'subcategory' => 'client+server',
'detail' => 'complete cycle (udp/53 dns)',
'err_msg' => 'could not complete SPA cycle',
'function' => \&spa_cycle,
'cmdline' => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
"$fwknopCmd -A udp/53 -a $fake_ip -D $loopback_ip --get-key " .
"$local_key_file --verbose --verbose " .
"--gpg-recipient-key $gpg_server_key " .
"--gpg-signer-key $gpg_client_key " .
"--gpg-home-dir $gpg_client_home_dir_no_pw",
'fwknopd_cmdline' => $default_server_gpg_args_no_pw,
'fw_rule_created' => $NEW_RULE_REQUIRED,
'fw_rule_removed' => $NEW_RULE_REMOVED,
'fatal' => $NO
},
{
'category' => 'GPG (no pw) SPA',
'subcategory' => 'client+server',
'detail' => 'replay attack detection',
'err_msg' => 'could not detect replay attack',
'function' => \&replay_detection,
'cmdline' => "$default_client_gpg_args_no_homedir "
. "--gpg-home-dir $gpg_client_home_dir_no_pw",
'fwknopd_cmdline' => $default_server_gpg_args_no_pw,
'replay_positive_output_matches' => [qr/Replay\sdetected\sfrom\ssource\sIP/],
'fatal' => $NO
},
{
'category' => 'GPG (no pw) SPA',
'subcategory' => 'client+server',
'detail' => 'replay detection (GnuPG prefix)',
'err_msg' => 'could not detect replay attack',
'function' => \&replay_detection,
'pkt_prefix' => 'hQ',
'cmdline' => "$default_client_gpg_args_no_homedir "
. "--gpg-home-dir $gpg_client_home_dir_no_pw",
'fwknopd_cmdline' => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
"$fwknopdCmd $default_server_conf_args $intf_str",
'replay_positive_output_matches' => [qr/Data\sis\snot\sa\svalid\sSPA\smessage\sformat/],
'fatal' => $NO
},
{
'category' => 'GPG (no pw) SPA',
'subcategory' => 'client+server',
'detail' => 'non-base64 altered SPA data',
'err_msg' => 'allowed improper SPA data',
'function' => \&altered_non_base64_spa_data,
'cmdline' => "$default_client_gpg_args_no_homedir "
. "--gpg-home-dir $gpg_client_home_dir_no_pw",
'fwknopd_cmdline' => $default_server_gpg_args_no_pw,
'fatal' => $NO
},
{
'category' => 'GPG (no pw) SPA',
'subcategory' => 'client+server',
'detail' => 'base64 altered SPA data',
'err_msg' => 'allowed improper SPA data',
'function' => \&altered_base64_spa_data,
'cmdline' => "$default_client_gpg_args_no_homedir "
. "--gpg-home-dir $gpg_client_home_dir_no_pw",
'fwknopd_cmdline' => $default_server_gpg_args_no_pw,
'fatal' => $NO
},
{
'category' => 'GPG (no pw) SPA',
'subcategory' => 'client+server',
'detail' => 'appended data to SPA pkt',
'err_msg' => 'allowed improper SPA data',
'function' => \&appended_spa_data,
'cmdline' => "$default_client_gpg_args_no_homedir "
. "--gpg-home-dir $gpg_client_home_dir_no_pw",
'fwknopd_cmdline' => $default_server_gpg_args_no_pw,
'fatal' => $NO
},
{
'category' => 'GPG (no pw) SPA',
'subcategory' => 'client+server',
'detail' => 'prepended data to SPA pkt',
'err_msg' => 'allowed improper SPA data',
'function' => \&prepended_spa_data,
'cmdline' => "$default_client_gpg_args_no_homedir "
. "--gpg-home-dir $gpg_client_home_dir_no_pw",
'fwknopd_cmdline' => $default_server_gpg_args_no_pw,
'fatal' => $NO
},
{
'category' => 'GPG (no pw) SPA',
'subcategory' => 'client+server',
'detail' => 'spoof username (tcp/22 ssh)',
'err_msg' => 'could not spoof username',
'function' => \&spoof_username,
'cmdline' => "SPOOF_USER=$spoof_user $default_client_gpg_args_no_homedir "
. "--gpg-home-dir $gpg_client_home_dir_no_pw",
'fwknopd_cmdline' => $default_server_gpg_args_no_pw,
'fatal' => $NO
},
{
'category' => 'GnuPG (GPG) SPA',
'subcategory' => 'client+server',
'detail' => 'complete cycle (tcp/22 ssh)',
'err_msg' => 'could not complete SPA cycle',
'function' => \&spa_cycle,
'cmdline' => $default_client_gpg_args,
'fwknopd_cmdline' => $default_server_gpg_args,
'fw_rule_created' => $NEW_RULE_REQUIRED,
'fw_rule_removed' => $NEW_RULE_REMOVED,
'fatal' => $NO
},
{
'category' => 'GnuPG (GPG) SPA',
'subcategory' => 'client+server',
'detail' => 'multi gpg-IDs (tcp/22 ssh)',
'err_msg' => 'could not complete SPA cycle',
'function' => \&spa_cycle,
'cmdline' => $default_client_gpg_args,
'fwknopd_cmdline' => "LD_LIBRARY_PATH=$lib_dir " .
"$valgrind_str $fwknopdCmd -c $cf{'def'} " .
"-a $cf{'multi_gpg_access'} $intf_str " .
"-d $default_digest_file -p $default_pid_file",
'fw_rule_created' => $NEW_RULE_REQUIRED,
'fw_rule_removed' => $NEW_RULE_REMOVED,
'fatal' => $NO
},
{
'category' => 'GnuPG (GPG) SPA',
'subcategory' => 'client+server',
'detail' => 'complete cycle (tcp/23 telnet)',
'err_msg' => 'could not complete SPA cycle',
'function' => \&spa_cycle,
'cmdline' => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
"$fwknopCmd -A tcp/23 -a $fake_ip -D $loopback_ip --get-key " .
"$local_key_file --verbose --verbose " .
"--gpg-recipient-key $gpg_server_key " .
"--gpg-signer-key $gpg_client_key " .
"--gpg-home-dir $gpg_client_home_dir",
'fwknopd_cmdline' => $default_server_gpg_args,
'fw_rule_created' => $NEW_RULE_REQUIRED,
'fw_rule_removed' => $NEW_RULE_REMOVED,
'fatal' => $NO
},
{
'category' => 'GnuPG (GPG) SPA',
'subcategory' => 'client+server',
'detail' => 'complete cycle (tcp/9418 git)',
'err_msg' => 'could not complete SPA cycle',
'function' => \&spa_cycle,
'cmdline' => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
"$fwknopCmd -A tcp/9418 -a $fake_ip -D $loopback_ip --get-key " .
"$local_key_file --verbose --verbose " .
"--gpg-recipient-key $gpg_server_key " .
"--gpg-signer-key $gpg_client_key " .
"--gpg-home-dir $gpg_client_home_dir",
'fwknopd_cmdline' => $default_server_gpg_args,
'fw_rule_created' => $NEW_RULE_REQUIRED,
'fw_rule_removed' => $NEW_RULE_REMOVED,
'fatal' => $NO
},
{
'category' => 'GnuPG (GPG) SPA',
'subcategory' => 'client+server',
'detail' => 'complete cycle (tcp/60001)',
'err_msg' => 'could not complete SPA cycle',
'function' => \&spa_cycle,
'cmdline' => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
"$fwknopCmd -A tcp/60001 -a $fake_ip -D $loopback_ip --get-key " .
"$local_key_file --verbose --verbose " .
"--gpg-recipient-key $gpg_server_key " .
"--gpg-signer-key $gpg_client_key " .
"--gpg-home-dir $gpg_client_home_dir",
'fwknopd_cmdline' => $default_server_gpg_args,
'fw_rule_created' => $NEW_RULE_REQUIRED,
'fw_rule_removed' => $NEW_RULE_REMOVED,
'fatal' => $NO
},
{
'category' => 'GnuPG (GPG) SPA',
'subcategory' => 'client+server',
'detail' => 'complete cycle (udp/53 dns)',
'err_msg' => 'could not complete SPA cycle',
'function' => \&spa_cycle,
'cmdline' => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
"$fwknopCmd -A udp/53 -a $fake_ip -D $loopback_ip --get-key " .
"$local_key_file --verbose --verbose " .
"--gpg-recipient-key $gpg_server_key " .
"--gpg-signer-key $gpg_client_key " .
"--gpg-home-dir $gpg_client_home_dir",
'fwknopd_cmdline' => $default_server_gpg_args,
'fw_rule_created' => $NEW_RULE_REQUIRED,
'fw_rule_removed' => $NEW_RULE_REMOVED,
'fatal' => $NO
},
{
'category' => 'GnuPG (GPG) SPA',
'subcategory' => 'client+server',
'detail' => 'replay attack detection',
'err_msg' => 'could not detect replay attack',
'function' => \&replay_detection,
'cmdline' => $default_client_gpg_args,
'fwknopd_cmdline' => $default_server_gpg_args,
'replay_positive_output_matches' => [qr/Replay\sdetected\sfrom\ssource\sIP/],
'fatal' => $NO
},
{
'category' => 'GnuPG (GPG) SPA',
'subcategory' => 'client+server',
'detail' => 'replay detection (GnuPG prefix)',
'err_msg' => 'could not detect replay attack',
'function' => \&replay_detection,
'pkt_prefix' => 'hQ',
'cmdline' => $default_client_gpg_args,
'fwknopd_cmdline' => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
"$fwknopdCmd $default_server_conf_args $intf_str",
'replay_positive_output_matches' => [qr/Data\sis\snot\sa\svalid\sSPA\smessage\sformat/],
'fatal' => $NO
},
{
'category' => 'GnuPG (GPG) SPA',
'subcategory' => 'client+server',
'detail' => 'non-base64 altered SPA data',
'err_msg' => 'allowed improper SPA data',
'function' => \&altered_non_base64_spa_data,
'cmdline' => $default_client_gpg_args,
'fwknopd_cmdline' => $default_server_gpg_args,
'fatal' => $NO
},
{
'category' => 'GnuPG (GPG) SPA',
'subcategory' => 'client+server',
'detail' => 'base64 altered SPA data',
'err_msg' => 'allowed improper SPA data',
'function' => \&altered_base64_spa_data,
'cmdline' => $default_client_gpg_args,
'fwknopd_cmdline' => $default_server_gpg_args,
'fatal' => $NO
},
{
'category' => 'GnuPG (GPG) SPA',
'subcategory' => 'client+server',
'detail' => 'appended data to SPA pkt',
'err_msg' => 'allowed improper SPA data',
'function' => \&appended_spa_data,
'cmdline' => $default_client_gpg_args,
'fwknopd_cmdline' => $default_server_gpg_args,
'fatal' => $NO
},
{
'category' => 'GnuPG (GPG) SPA',
'subcategory' => 'client+server',
'detail' => 'prepended data to SPA pkt',
'err_msg' => 'allowed improper SPA data',
'function' => \&prepended_spa_data,
'cmdline' => $default_client_gpg_args,
'fwknopd_cmdline' => $default_server_gpg_args,
'fatal' => $NO
},
{
'category' => 'GnuPG (GPG) SPA',
'subcategory' => 'client+server',
'detail' => 'spoof username (tcp/22 ssh)',
'err_msg' => 'could not spoof username',
'function' => \&spoof_username,
'cmdline' => "SPOOF_USER=$spoof_user $default_client_gpg_args",
'fwknopd_cmdline' => $default_server_gpg_args,
'fatal' => $NO
},
{
'category' => 'GnuPG (GPG) SPA',
'subcategory' => 'server',
'detail' => 'digest cache structure',
'err_msg' => 'improper digest cache structure',
'function' => \&digest_cache_structure,
'fatal' => $NO
},
);
if ($use_valgrind) {
push @tests,
{
'category' => 'valgrind output',
'subcategory' => 'flagged functions',
'detail' => '',
'err_msg' => 'could not parse flagged functions',
'function' => \&parse_valgrind_flagged_functions,
'fatal' => $NO
};
}
my %test_keys = (
'category' => $REQUIRED,
'subcategory' => $OPTIONAL,
'detail' => $REQUIRED,
'function' => $REQUIRED,
'binary' => $OPTIONAL,
'cmdline' => $OPTIONAL,
'fwknopd_cmdline' => $OPTIONAL,
'fatal' => $OPTIONAL,
'exec_err' => $OPTIONAL,
'fw_rule_created' => $OPTIONAL,
'fw_rule_removed' => $OPTIONAL,
'server_conf' => $OPTIONAL,
'pkt_prefix' => $OPTIONAL,
'no_ip_check' => $OPTIONAL,
'positive_output_matches' => $OPTIONAL,
'negative_output_matches' => $OPTIONAL,
'server_positive_output_matches' => $OPTIONAL,
'server_negative_output_matches' => $OPTIONAL,
'replay_positive_output_matches' => $OPTIONAL,
'replay_negative_output_matches' => $OPTIONAL,
);
if ($diff_mode) {
&diff_test_results();
exit 0;
}
### make sure everything looks as expected before continuing
&init();
&logr("\n[+] Starting the fwknop test suite...\n\n" .
" args: @args_cp\n\n"
);
### save the results from any previous test suite run
### so that we can potentially compare them with --diff
if ($saved_last_results) {
&logr(" Saved results from previous run " .
"to: ${output_dir}.last/\n\n");
}
### main loop through all of the tests
for my $test_hr (@tests) {
&run_test($test_hr);
}
&logr("\n[+] passed/failed/executed: $passed/$failed/$executed tests\n\n");
copy $logfile, "$output_dir/$logfile" or die $!;
exit 0;
#===================== end main =======================
sub run_test() {
my $test_hr = shift;
my $msg = "[$test_hr->{'category'}]";
$msg .= " [$test_hr->{'subcategory'}]" if $test_hr->{'subcategory'};
$msg .= " $test_hr->{'detail'}";
return unless &process_include_exclude($msg);
if ($list_mode) {
print $msg, "\n";
return;
}
&dots_print($msg);
$executed++;
$current_test_file = "$output_dir/$executed.test";
$server_test_file = "$output_dir/${executed}_fwknopd.test";
&write_test_file("[+] TEST: $msg\n", $current_test_file);
$test_hr->{'msg'} = $msg;
if (&{$test_hr->{'function'}}($test_hr)) {
&logr("pass ($executed)\n");
$passed++;
} else {
&logr("fail ($executed)\n");
$failed++;
if ($test_hr->{'fatal'} eq $YES) {
die "[*] required test failed, exiting.";
}
}
return;
}
sub process_include_exclude() {
my $msg = shift;
### inclusions/exclusions
if (@tests_to_include) {
my $found = 0;
for my $test (@tests_to_include) {
if ($msg =~ $test or ($use_valgrind
and $msg =~ /valgrind\soutput/)) {
$found = 1;
last;
}
}
return 0 unless $found;
}
if (@tests_to_exclude) {
my $found = 0;
for my $test (@tests_to_exclude) {
if ($msg =~ $test) {
$found = 1;
last;
}
}
return 0 if $found;
}
return 1;
}
sub diff_test_results() {
$diff_dir1 = "${output_dir}.last" unless $diff_dir1;
$diff_dir2 = $output_dir unless $diff_dir2;
die "[*] Need results from a previous run before running --diff"
unless -d $diff_dir2;
die "[*] Current results set does not exist." unless -d $diff_dir1;
my %current_tests = ();
my %previous_tests = ();
### Only diff results for matching tests (parse the logfile to see which
### test numbers match across the two test cycles).
&build_results_hash(\%current_tests, $diff_dir1);
&build_results_hash(\%previous_tests, $diff_dir2);
for my $test_msg (sort {$current_tests{$a}{'num'} <=> $current_tests{$b}{'num'}}
keys %current_tests) {
my $current_result = $current_tests{$test_msg}{'pass_fail'};
my $current_num = $current_tests{$test_msg}{'num'};
if (defined $previous_tests{$test_msg}) {
print "[+] Checking: $test_msg\n";
my $previous_result = $previous_tests{$test_msg}{'pass_fail'};
my $previous_num = $previous_tests{$test_msg}{'num'};
if ($current_result ne $previous_result) {
print " DIFF: **$current_result** $test_msg\n";
}
&diff_results($previous_num, $current_num);
print "\n";
}
}
exit 0;
}
sub diff_results() {
my ($previous_num, $current_num) = @_;
### edit out any valgrind "==354==" prefixes
my $valgrind_search_re = qr/^==\d+==\s/;
### remove CMD timestamps
my $cmd_search_re = qr/^\S+\s.*?\s\d{4}\sCMD\:/;
for my $file ("$diff_dir1/${previous_num}.test",
"$diff_dir1/${previous_num}_fwknopd.test",
"$diff_dir2/${current_num}.test",
"$diff_dir2/${current_num}_fwknopd.test",
) {
system qq{perl -p -i -e 's|$valgrind_search_re||' $file} if -e $file;
system qq{perl -p -i -e 's|$cmd_search_re|CMD:|' $file} if -e $file;
}
if (-e "$diff_dir1/${previous_num}.test"
and -e "$diff_dir2/${current_num}.test") {
system "diff -u $diff_dir1/${previous_num}.test " .
"$diff_dir2/${current_num}.test";
}
if (-e "$diff_dir1/${previous_num}_fwknopd.test"
and -e "$diff_dir2/${current_num}_fwknopd.test") {
system "diff -u $diff_dir1/${previous_num}_fwknopd.test " .
"$diff_dir2/${current_num}_fwknopd.test";
}
return;
}
sub build_results_hash() {
my ($hr, $dir) = @_;
open F, "< $dir/$logfile" or die $!;
while (<F>) {
if (/^(.*?)\.\.\..*(pass|fail)\s\((\d+)\)/) {
$hr->{$1}{'pass_fail'} = $2;
$hr->{$1}{'num'} = $3;
}
}
return;
}
sub compile_warnings() {
### 'make clean' as root
return 0 unless &run_cmd('make -C .. clean',
$cmd_out_tmp, $current_test_file);
if ($sudo_path) {
my $username = getpwuid((stat($configure_path))[4]);
die "[*] Could not determine $configure_path owner"
unless $username;
return 0 unless &run_cmd("$sudo_path -u $username make -C ..",
$cmd_out_tmp, $current_test_file);
} else {
return 0 unless &run_cmd('make -C ..',
$cmd_out_tmp, $current_test_file);
}
### 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/],
$MATCH_ANY, $current_test_file);
### the new binaries should exist
unless (-e $fwknopCmd and -x $fwknopCmd) {
&write_test_file("[-] $fwknopCmd does not exist or not executable.\n",
$current_test_file);
}
unless (-e $fwknopdCmd and -x $fwknopdCmd) {
&write_test_file("[-] $fwknopdCmd does not exist or not executable.\n",
$current_test_file);
}
return 1;
}
sub make_distcheck() {
### 'make clean' as root
return 0 unless &run_cmd('make -C .. distcheck',
$cmd_out_tmp, $current_test_file);
### look for compilation warnings - something like:
### warning: ‘test’ is used uninitialized in this function
return 1 if &file_find_regex([qr/archives\sready\sfor\sdistribution/],
$MATCH_ALL, $current_test_file);
return 0;
}
sub binary_exists() {
my $test_hr = shift;
return 0 unless $test_hr->{'binary'};
### account for different libfko.so paths (e.g. libfko.so.0.3 with no
### libfko.so link on OpenBSD, and libfko.dylib path on Mac OS X)
if ($test_hr->{'binary'} =~ /libfko/) {
unless (-e $test_hr->{'binary'}) {
my $file = "$lib_dir/libfko.dylib";
if (-e $file) {
$test_hr->{'binary'} = $file;
$libfko_bin = $file;
} else {
for my $f (glob("$lib_dir/libfko.so*")) {
if (-e $f and -x $f) {
$test_hr->{'binary'} = $f;
$libfko_bin = $f;
last;
}
}
}
}
}
return 0 unless -e $test_hr->{'binary'} and -x $test_hr->{'binary'};
return 1;
}
sub expected_code_version() {
my $test_hr = shift;
unless (-e '../VERSION') {
&write_test_file("[-] ../VERSION file does not exist.\n",
$current_test_file);
return 0;
}
open F, '< ../VERSION' or die $!;
my $line = <F>;
close F;
if ($line =~ /(\d.*\d)/) {
my $version = $1;
return 0 unless &run_cmd($test_hr->{'cmdline'},
$cmd_out_tmp, $current_test_file);
return 1 if &file_find_regex([qr/$version/],
$MATCH_ALL, $current_test_file);
}
return 0;
}
sub client_send_spa_packet() {
my $test_hr = shift;
&write_key('fwknoptest', $local_key_file);
return 0 unless &run_cmd($test_hr->{'cmdline'},
$cmd_out_tmp, $current_test_file);
return 0 unless &file_find_regex([qr/final\spacked/i],
$MATCH_ALL, $current_test_file);
return 1;
}
sub permissions_check() {
my $test_hr = shift;
my $rv = 0;
chmod 0777, $cf{'def'} or die $!;
chmod 0777, $cf{'def_access'} or die $!;
$rv = &spa_cycle($test_hr);
chmod 0600, $cf{'def'} or die $!;
chmod 0600, $cf{'def_access'} or die $!;
if ($test_hr->{'server_positive_output_matches'}) {
$rv = 0 unless &file_find_regex(
$test_hr->{'server_positive_output_matches'},
$MATCH_ALL, $server_test_file);
}
return $rv;
}
sub spa_cycle() {
my $test_hr = shift;
my ($rv, $server_was_stopped, $fw_rule_created, $fw_rule_removed)
= &client_server_interaction($test_hr, [], $USE_CLIENT);
if ($test_hr->{'fw_rule_created'} eq $NEW_RULE_REQUIRED) {
$rv = 0 unless $fw_rule_created;
} elsif ($test_hr->{'fw_rule_created'} eq $REQUIRE_NO_NEW_RULE) {
$rv = 0 if $fw_rule_created;
}
if ($test_hr->{'fw_rule_removed'} eq $NEW_RULE_REMOVED) {
$rv = 0 unless $fw_rule_removed;
} elsif ($test_hr->{'fw_rule_removed'} eq $REQUIRE_NO_NEW_REMOVED) {
$rv = 0 if $fw_rule_removed;
}
if ($test_hr->{'server_positive_output_matches'}) {
$rv = 0 unless &file_find_regex(
$test_hr->{'server_positive_output_matches'},
$MATCH_ALL, $server_test_file);
}
if ($test_hr->{'server_negative_output_matches'}) {
$rv = 0 if &file_find_regex(
$test_hr->{'server_negative_output_matches'},
$MATCH_ANY, $server_test_file);
}
return $rv;
}
sub spoof_username() {
my $test_hr = shift;
my $rv = &spa_cycle($test_hr);
unless (&file_find_regex([qr/Username:\s*$spoof_user/],
$MATCH_ALL, $current_test_file)) {
$rv = 0;
}
unless (&file_find_regex([qr/Username:\s*$spoof_user/],
$MATCH_ALL, $server_test_file)) {
$rv = 0;
}
return $rv;
}
sub perl_fko_module_compile_install() {
my $test_hr = shift;
my $rv = 1;
if (-d $perl_mod_fko_dir) {
rmtree $perl_mod_fko_dir or die $!;
}
mkdir $perl_mod_fko_dir or die "[*] Could not mkdir $perl_mod_fko_dir: $!";
my $curr_pwd = cwd() or die $!;
chdir '../perl/FKO' or die $!;
&run_cmd("make clean", $cmd_out_tmp,
"../../test/$current_test_file");
&run_cmd("perl Makefile.PL PREFIX=../../test/$perl_mod_fko_dir " .
"LIB=../../test/$perl_mod_fko_dir", $cmd_out_tmp,
"../../test/$current_test_file");
&run_cmd('make', $cmd_out_tmp,
"../../test/$current_test_file");
&run_cmd('make install', $cmd_out_tmp,
"../../test/$current_test_file");
chdir $curr_pwd or die $!;
my $mod_paths_ar = &get_mod_paths();
if ($#$mod_paths_ar > -1) { ### FKO/ exists
push @$mod_paths_ar, @INC;
splice @INC, 0, $#$mod_paths_ar+1, @$mod_paths_ar;
}
eval { require FKO };
if ($@) {
&write_test_file("[-] could not 'require FKO' module: $@\n",
$current_test_file);
$rv = 0;
### disable remaining perl module checks
push @tests_to_exclude, qr/perl FKO module/;
}
return $rv;
}
sub perl_fko_module_new_object() {
my $test_hr = shift;
my $rv = 1;
$fko_obj = FKO->new();
if ($fko_obj) {
$fko_obj->destroy();
} else {
&write_test_file("[-] error FKO->new(): " . FKO::error_str() . "\n",
$current_test_file);
### disable remaining perl module checks
push @tests_to_exclude, qr/perl FKO module/;
$rv = 0;
}
return $rv;
}
sub perl_fko_module_new_objects_1000() {
my $test_hr = shift;
my $rv = 1;
for (my $i=0; $i < 1000; $i++) {
$fko_obj = FKO->new();
if ($fko_obj) {
$fko_obj->destroy();
} else {
&write_test_file("[-] error FKO->new(): " . FKO::error_str() . "\n",
$current_test_file);
### disable remaining perl module checks
push @tests_to_exclude, qr/perl FKO module/;
$rv = 0;
last;
}
}
return $rv;
}
sub perl_fko_module_version() {
my $test_hr = shift;
my $rv = 1;
$fko_obj = FKO->new();
unless ($fko_obj) {
&write_test_file("[-] error FKO->new(): " . FKO::error_str() . "\n",
$current_test_file);
return 0;
}
my $version = $fko_obj->version();
if ($version) {
&write_test_file("[+] got version(): $version\n",
$current_test_file);
} else {
&write_test_file("[-] could not get version()\n",
$current_test_file);
$rv = 0;
}
$fko_obj->destroy();
return $rv;
}
sub perl_fko_module_rand() {
my $test_hr = shift;
my $rv = 1;
$fko_obj = FKO->new();
unless ($fko_obj) {
&write_test_file("[-] error FKO->new(): " . FKO::error_str() . "\n",
$current_test_file);
return 0;
}
my $rand_value = $fko_obj->rand_value();
if ($rand_value) {
&write_test_file("[+] got rand_value(): $rand_value\n",
$current_test_file);
} else {
&write_test_file("[-] could not get rand_value()\n",
$current_test_file);
$rv = 0;
}
$fko_obj->destroy();
return $rv;
}
sub perl_fko_module_user() {
my $test_hr = shift;
my $rv = 1;
$fko_obj = FKO->new();
unless ($fko_obj) {
&write_test_file("[-] error FKO->new(): " . FKO::error_str() . "\n",
$current_test_file);
return 0;
}
my $username = $fko_obj->username();
if ($username) {
&write_test_file("[+] got username(): $username\n",
$current_test_file);
} else {
&write_test_file("[-] could not get username()\n",
$current_test_file);
$rv = 0;
}
### set the username and check it
my $status = $fko_obj->username('test');
if ($status == FKO->FKO_SUCCESS and $fko_obj->username() eq 'test') {
&write_test_file("[+] get/set username(): test\n",
$current_test_file);
} else {
&write_test_file("[-] could not get/set username(): test " .
FKO::error_str() . "\n",
$current_test_file);
$rv = 0;
}
for my $bogus_user (
'A'x1000,
"-1",
-1,
pack('a', ""),
'123%123'
) {
### set the username to something bogus and make sure libfko rejects it
$status = $fko_obj->username($bogus_user);
if ($status == FKO->FKO_SUCCESS and $fko_obj->username() eq $bogus_user) {
&write_test_file("[-] libfko allowed bogus username(): $bogus_user " .
FKO::error_str() . "\n",
$current_test_file);
$rv = 0;
} else {
&write_test_file("[+] libfko threw out bogus username(): $bogus_user\n",
$current_test_file);
}
}
$fko_obj->destroy();
return $rv;
}
sub perl_fko_module_timestamp() {
my $test_hr = shift;
my $rv = 1;
$fko_obj = FKO->new();
unless ($fko_obj) {
&write_test_file("[-] error FKO->new(): " . FKO::error_str() . "\n",
$current_test_file);
return 0;
}
my $timestamp = $fko_obj->timestamp();
if ($timestamp) {
&write_test_file("[+] got timestamp(): $timestamp\n",
$current_test_file);
} else {
&write_test_file("[-] could not get timestamp()\n",
$current_test_file);
$rv = 0;
}
$fko_obj->destroy();
return $rv;
}
sub perl_fko_module_msg_types() {
my $test_hr = shift;
my $rv = 1;
$fko_obj = FKO->new();
unless ($fko_obj) {
&write_test_file("[-] error FKO->new(): " . FKO::error_str() . "\n",
$current_test_file);
return 0;
}
my $msg_type = -1;
### default
$msg_type = $fko_obj->spa_message_type();
if ($msg_type > -1) {
&write_test_file("[+] got default spa_message_type(): $msg_type\n",
$current_test_file);
} else {
&write_test_file("[-] could not get default spa_message_type()\n",
$current_test_file);
$rv = 0;
}
for my $type (
FKO->FKO_ACCESS_MSG,
FKO->FKO_COMMAND_MSG,
FKO->FKO_LOCAL_NAT_ACCESS_MSG,
FKO->FKO_NAT_ACCESS_MSG,
FKO->FKO_CLIENT_TIMEOUT_ACCESS_MSG,
FKO->FKO_CLIENT_TIMEOUT_NAT_ACCESS_MSG,
FKO->FKO_CLIENT_TIMEOUT_LOCAL_NAT_ACCESS_MSG,
) {
### set message type and then see if it matches
my $status = $fko_obj->spa_message_type($type);
if ($status == FKO->FKO_SUCCESS and $fko_obj->spa_message_type() == $type) {
&write_test_file("[+] get/set spa_message_type(): $type\n",
$current_test_file);
} else {
&write_test_file("[-] could not get/set spa_message_type(): $type " .
FKO::error_str() . "\n",
$current_test_file);
$rv = 0;
last;
}
}
for my $bogus_type (
-1,
255,
) {
### set message type and then see if it matches
my $status = $fko_obj->spa_message_type($bogus_type);
if ($status == FKO->FKO_SUCCESS) {
&write_test_file("[-] libfko allowed bogus spa_message_type(): $bogus_type " .
FKO::error_str() . "\n",
$current_test_file);
$rv = 0;
} else {
&write_test_file("[+] libfko rejected bogus spa_message_type(): $bogus_type\n",
$current_test_file);
}
}
$fko_obj->destroy();
return $rv;
}
sub perl_fko_module_msg() {
my $test_hr = shift;
my $rv = 1;
$fko_obj = FKO->new();
unless ($fko_obj) {
&write_test_file("[-] error FKO->new(): " . FKO::error_str() . "\n",
$current_test_file);
return 0;
}
for my $msg (
'1.2.3.4,tcp/22',
'1.2.3.4,udp/53',
'123.123.123.123,tcp/12345',
'123.123.123.123,udp/12345'
) {
### set message and then see if it matches
my $status = $fko_obj->spa_message($msg);
if ($status == FKO->FKO_SUCCESS and $fko_obj->spa_message() eq $msg) {
&write_test_file("[+] get/set spa_message(): $msg\n",
$current_test_file);
} else {
&write_test_file("[-] could not get/set spa_message(): $msg " .
FKO::error_str() . "\n",
$current_test_file);
$rv = 0;
last;
}
}
for my $bogus_msg (@{&bogus_access_messages()}) {
### set message type and then see if it matches
my $status = $fko_obj->spa_message($bogus_msg);
if ($status == FKO->FKO_SUCCESS) {
&write_test_file("[-] libfko allowed bogus " .
"spa_message(): $bogus_msg, got: " . $fko_obj->spa_message() . ' ' .
FKO::error_str() . "\n",
$current_test_file);
$rv = 0;
} else {
&write_test_file("[+] libfko rejected bogus spa_message(): $bogus_msg\n",
$current_test_file);
}
}
$fko_obj->destroy();
return $rv;
}
sub bogus_access_messages() {
my @msgs = (
'1.2.3.4,tcp/2a2',
'1.2.3.4,tcp/22,',
'1.2.3.4,tcp/123456',
'1.2.3.4,tcp/123456' . '9'x100,
'1.2.3.4,tcp//22',
'1.2.3.4,tcp/22/',
'a23.123.123.123,tcp/12345',
-1,
1,
'A',
0x0,
'A'x1000,
'/'x1000,
'%'x1000,
':'x1000,
pack('a', ""),
'1.1.1.p/12345',
'1.1.1.2,,,,12345',
'1.1.1.2,12345',
'1.1.1.2,icmp/123',
',,,',
'----',
'1.3.4.5.5',
'1.3.4.5,' . '/'x100,
'1.3.4.5,' . '/'x100 . '22',
'1.2.3.4,rcp/22',
'1.2.3.4,udp/-1',
'1.2.3.4,tcp/-1',
'1.2.3.4,icmp/-1',
'1.2.3' . pack('a', "") . '.4,tcp/22',
'1.2.3.' . pack('a', "") . '4,tcp/22',
'1.2.3.4' . pack('a', "") . ',tcp/22',
'1.2.3.4,' . pack('a', "") . 'tcp/22',
'1.2.3.4,t' . pack('a', "") . 'cp/22',
'1.2.3.4,tc' . pack('a', "") . 'p/22',
'1.2.3.4,tcp' . pack('a', "") . '/22',
'1.2.3.4,tcp/' . pack('a', "") . '22',
'123.123.123' . pack('a', "") . '.123,tcp/22',
'123.123.123.' . pack('a', "") . '123,tcp/22',
'123.123.123.1' . pack('a', "") . '23,tcp/22',
'123.123.123.12' . pack('a', "") . '3,tcp/22',
'123.123.123.123' . pack('a', "") . ',tcp/22',
'123.123.123.123,' . pack('a', "") . 'tcp/22',
'123.123.123.123,t' . pack('a', "") . 'cp/22',
'123.123.123.123,tc' . pack('a', "") . 'p/22',
'123.123.123.123,tcp' . pack('a', "") . '/22',
'123.123.123.123,tcp/' . pack('a', "") . '22',
'1.2.3.4,t' . pack('a', "") . 'cp/22'
);
return \@msgs;
}
sub perl_fko_module_client_compatibility() {
my $test_hr = shift;
my $rv = 1;
$fko_obj = FKO->new();
unless ($fko_obj) {
&write_test_file("[-] error FKO->new(): " . FKO::error_str() . "\n",
$current_test_file);
return 0;
}
$fko_obj->destroy();
return $rv;
}
sub get_mod_paths() {
my @paths = ();
opendir D, $perl_mod_fko_dir
or die "[*] Could not open $perl_mod_fko_dir: $!";
my @dirs = readdir D;
closedir D;
push @paths, $perl_mod_fko_dir;
for my $dir (@dirs) {
### get directories like "FKO/x86_64-linux"
next unless -d "$perl_mod_fko_dir/$dir";
push @paths, "$perl_mod_fko_dir/$dir"
if $dir =~ m|linux| or $dir =~ m|thread|
or (-d "$perl_mod_fko_dir/$dir/auto");
}
return \@paths;
}
sub spa_cmd_exec_cycle() {
my $test_hr = shift;
my $rv = &spa_cycle($test_hr);
if (-e $cmd_exec_test_file) {
unlink $cmd_exec_test_file;
} else {
$rv = 0;
}
return $rv;
}
sub replay_detection() {
my $test_hr = shift;
### do a complete SPA cycle and then parse the SPA packet out of the
### current test file and re-send
return 0 unless &spa_cycle($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",
$current_test_file);
return 0;
}
if ($test_hr->{'pkt_prefix'}) {
$spa_pkt = $test_hr->{'pkt_prefix'} . $spa_pkt;
}
my @packets = (
{
'proto' => 'udp',
'port' => $default_spa_port,
'dst_ip' => $loopback_ip,
'data' => $spa_pkt,
},
);
my ($rv, $server_was_stopped, $fw_rule_created, $fw_rule_removed)
= &client_server_interaction($test_hr, \@packets, $USE_PREDEF_PKTS);
$rv = 0 unless $server_was_stopped;
if ($test_hr->{'replay_positive_output_matches'}) {
$rv = 0 unless &file_find_regex(
$test_hr->{'replay_positive_output_matches'},
$MATCH_ALL, $server_test_file);
}
if ($test_hr->{'replay_negative_output_matches'}) {
$rv = 0