(Fernando Arnaboldi, IOActive) Found and fixed several DoS/code execution vulns for...
[fwknop.git] / test / test-fwknop.pl
1 #!/usr/bin/perl -w
2
3 use File::Copy;
4 use File::Path;
5 use IO::Socket;
6 use Data::Dumper;
7 use Getopt::Long 'GetOptions';
8 use strict;
9
10 #==================== config =====================
11 my $logfile        = 'test.log';
12 my $local_key_file = 'local_spa.key';
13 my $output_dir     = 'output';
14 my $lib_dir        = '../lib/.libs';
15 my $conf_dir       = 'conf';
16 my $run_dir        = 'run';
17 my $configure_path = '../configure';
18 my $cmd_out_tmp    = 'cmd.out';
19 my $server_cmd_tmp = 'server_cmd.out';
20 my $gpg_client_home_dir = "$conf_dir/client-gpg";
21 my $gpg_client_home_dir_no_pw = "$conf_dir/client-gpg-no-pw";
22
23 my %cf = (
24     'nat'                  => "$conf_dir/nat_fwknopd.conf",
25     'def'                  => "$conf_dir/default_fwknopd.conf",
26     'def_access'           => "$conf_dir/default_access.conf",
27     'exp_access'           => "$conf_dir/expired_stanza_access.conf",
28     'future_exp_access'    => "$conf_dir/future_expired_stanza_access.conf",
29     'exp_epoch_access'     => "$conf_dir/expired_epoch_stanza_access.conf",
30     'invalid_exp_access'   => "$conf_dir/invalid_expire_access.conf",
31     'force_nat_access'     => "$conf_dir/force_nat_access.conf",
32     'local_nat'            => "$conf_dir/local_nat_fwknopd.conf",
33     'ipfw_active_expire'   => "$conf_dir/ipfw_active_expire_equal_fwknopd.conf",
34     'dual_key_access'      => "$conf_dir/dual_key_usage_access.conf",
35     'gpg_access'           => "$conf_dir/gpg_access.conf",
36     'gpg_no_pw_access'     => "$conf_dir/gpg_no_pw_access.conf",
37     'open_ports_access'    => "$conf_dir/open_ports_access.conf",
38     'multi_gpg_access'     => "$conf_dir/multi_gpg_access.conf",
39     'multi_stanza_access'  => "$conf_dir/multi_stanzas_access.conf",
40     'broken_keys_access'   => "$conf_dir/multi_stanzas_with_broken_keys.conf",
41     'open_ports_mismatch'  => "$conf_dir/mismatch_open_ports_access.conf",
42     'require_user_access'  => "$conf_dir/require_user_access.conf",
43     'user_mismatch_access' => "$conf_dir/mismatch_user_access.conf",
44     'require_src_access'   => "$conf_dir/require_src_access.conf",
45     'no_src_match'         => "$conf_dir/no_source_match_access.conf",
46     'no_subnet_match'      => "$conf_dir/no_subnet_source_match_access.conf",
47     'no_multi_src'         => "$conf_dir/no_multi_source_match_access.conf",
48     'multi_src_access'     => "$conf_dir/multi_source_match_access.conf",
49     'ip_src_match'         => "$conf_dir/ip_source_match_access.conf",
50     'subnet_src_match'     => "$conf_dir/ip_source_match_access.conf",
51     'disable_aging'        => "$conf_dir/disable_aging_fwknopd.conf",
52 );
53
54 my $default_digest_file = "$run_dir/digest.cache";
55 my $default_pid_file    = "$run_dir/fwknopd.pid";
56
57 my $fwknopCmd   = '../client/.libs/fwknop';
58 my $fwknopdCmd  = '../server/.libs/fwknopd';
59 my $libfko_bin  = "$lib_dir/libfko.so";  ### this is usually a link
60 my $valgrindCmd = '/usr/bin/valgrind';
61
62 my $gpg_server_key = '361BBAD4';
63 my $gpg_client_key = '6A3FAD56';
64
65 my $loopback_ip = '127.0.0.1';
66 my $fake_ip     = '127.0.0.2';
67 my $internal_nat_host = '192.168.1.2';
68 my $force_nat_host = '192.168.1.123';
69 my $default_spa_port = 62201;
70 my $non_std_spa_port = 12345;
71
72 my $spoof_user = 'testuser';
73 #================== end config ===================
74
75 my $passed = 0;
76 my $failed = 0;
77 my $executed = 0;
78 my $test_include = '';
79 my @tests_to_include = ();
80 my $test_exclude = '';
81 my @tests_to_exclude = ();
82 my %valgrind_flagged_fcns = ();
83 my %valgrind_flagged_fcns_unique = ();
84 my $list_mode = 0;
85 my $diff_dir1 = '';
86 my $diff_dir2 = '';
87 my $loopback_intf = '';
88 my $anonymize_results = 0;
89 my $current_test_file = "$output_dir/init";
90 my $tarfile = 'test_fwknop.tar.gz';
91 my $server_test_file  = '';
92 my $use_valgrind = 0;
93 my $valgrind_str = '';
94 my $enable_client_ip_resolve_test = 0;
95 my $saved_last_results = 0;
96 my $diff_mode = 0;
97 my $enable_recompilation_warnings_check = 0;
98 my $enable_make_distcheck = 0;
99 my $sudo_path = '';
100 my $platform = '';
101 my $help = 0;
102 my $YES = 1;
103 my $NO  = 0;
104 my $PRINT_LEN = 68;
105 my $USE_PREDEF_PKTS = 1;
106 my $USE_CLIENT = 2;
107 my $REQUIRED = 1;
108 my $OPTIONAL = 0;
109 my $NEW_RULE_REQUIRED = 1;
110 my $REQUIRE_NO_NEW_RULE = 2;
111 my $NEW_RULE_REMOVED = 1;
112 my $REQUIRE_NO_NEW_REMOVED = 2;
113 my $MATCH_ANY = 1;
114 my $MATCH_ALL = 2;
115 my $LINUX   = 1;
116 my $FREEBSD = 2;
117 my $MACOSX  = 3;
118 my $OPENBSD = 4;
119
120 my $ip_re = qr|(?:[0-2]?\d{1,2}\.){3}[0-2]?\d{1,2}|;  ### IPv4
121
122 my @args_cp = @ARGV;
123
124 exit 1 unless GetOptions(
125     'Anonymize-results' => \$anonymize_results,
126     'fwknop-path=s'     => \$fwknopCmd,
127     'fwknopd-path=s'    => \$fwknopdCmd,
128     'libfko-path=s'     => \$libfko_bin,
129     'loopback-intf=s'   => \$loopback_intf,
130     'test-include=s'    => \$test_include,
131     'include=s'         => \$test_include,  ### synonym
132     'test-exclude=s'    => \$test_exclude,
133     'exclude=s'         => \$test_exclude,  ### synonym
134     'enable-recompile-check' => \$enable_recompilation_warnings_check,
135     'enable-ip-resolve' => \$enable_client_ip_resolve_test,
136     'enable-distcheck'  => \$enable_make_distcheck,
137     'List-mode'         => \$list_mode,
138     'enable-valgrind'   => \$use_valgrind,
139     'valgrind-path=s'   => \$valgrindCmd,
140     'output-dir=s'      => \$output_dir,
141     'diff'              => \$diff_mode,
142     'diff-dir1=s'       => \$diff_dir1,
143     'diff-dir2=s'       => \$diff_dir2,
144     'help'              => \$help
145 );
146
147 &usage() if $help;
148
149 ### create an anonymized tar file of test suite results that can be
150 ### emailed around to assist in debugging fwknop communications
151 exit &anonymize_results() if $anonymize_results;
152
153 &identify_loopback_intf();
154
155 $valgrind_str = "$valgrindCmd --leak-check=full " .
156     "--show-reachable=yes --track-origins=yes" if $use_valgrind;
157
158 my $intf_str = "-i $loopback_intf --foreground --verbose --verbose";
159
160 my $default_client_args = "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
161     "$fwknopCmd -A tcp/22 -a $fake_ip -D $loopback_ip --get-key " .
162     "$local_key_file --verbose --verbose";
163
164 my $client_ip_resolve_args = "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
165     "$fwknopCmd -A tcp/22 -R -D $loopback_ip --get-key " .
166     "$local_key_file --verbose --verbose";
167
168 my $default_client_gpg_args = "$default_client_args " .
169     "--gpg-recipient-key $gpg_server_key " .
170     "--gpg-signer-key $gpg_client_key " .
171     "--gpg-home-dir $gpg_client_home_dir";
172
173 my $default_client_gpg_args_no_homedir = "$default_client_args " .
174     "--gpg-recipient-key $gpg_server_key " .
175     "--gpg-signer-key $gpg_client_key ";
176
177 my $default_server_conf_args = "-c $cf{'def'} -a $cf{'def_access'} " .
178     "-d $default_digest_file -p $default_pid_file";
179
180 my $default_server_gpg_args = "LD_LIBRARY_PATH=$lib_dir " .
181     "$valgrind_str $fwknopdCmd -c $cf{'def'} " .
182     "-a $cf{'gpg_access'} $intf_str " .
183     "-d $default_digest_file -p $default_pid_file";
184
185 my $default_server_gpg_args_no_pw = "LD_LIBRARY_PATH=$lib_dir " .
186     "$valgrind_str $fwknopdCmd -c $cf{'def'} " .
187     "-a $cf{'gpg_no_pw_access'} $intf_str " .
188     "-d $default_digest_file -p $default_pid_file";
189
190 ### point the compiled binaries at the local libary path
191 ### instead of any installed libfko instance
192 $ENV{'LD_LIBRARY_PATH'} = $lib_dir;
193
194 ### main array that defines the tests we will run
195 my @tests = (
196     {
197         'category' => 'recompilation',
198         'detail'   => 'recompile and look for compilation warnings',
199         'err_msg'  => 'compile warnings exist',
200         'function' => \&compile_warnings,
201         'fatal'    => $NO
202     },
203     {
204         'category' => 'make distcheck',
205         'detail'   => 'ensure proper distribution creation',
206         'err_msg'  => 'could not create proper tarball',
207         'function' => \&make_distcheck,
208         'fatal'    => $NO
209     },
210     {
211         'category' => 'build',
212         'subcategory' => 'client',
213         'detail'   => 'binary exists',
214         'err_msg'  => 'binary not found',
215         'function' => \&binary_exists,
216         'binary'   => $fwknopCmd,
217         'fatal'    => $YES
218     },
219     {
220         'category' => 'build security',
221         'subcategory' => 'client',
222         'detail'   => 'Position Independent Executable (PIE)',
223         'err_msg'  => 'non PIE binary (fwknop client)',
224         'function' => \&pie_binary,
225         'binary'   => $fwknopCmd,
226         'fatal'    => $NO
227     },
228     {
229         'category' => 'build security',
230         'subcategory' => 'client',
231         'detail'   => 'stack protected binary',
232         'err_msg'  => 'non stack protected binary (fwknop client)',
233         'function' => \&stack_protected_binary,
234         'binary'   => $fwknopCmd,
235         'fatal'    => $NO
236     },
237     {
238         'category' => 'build security',
239         'subcategory' => 'client',
240         'detail'   => 'fortify source functions',
241         'err_msg'  => 'source functions not fortified (fwknop client)',
242         'function' => \&fortify_source_functions,
243         'binary'   => $fwknopCmd,
244         'fatal'    => $NO
245     },
246     {
247         'category' => 'build security',
248         'subcategory' => 'client',
249         'detail'   => 'read-only relocations',
250         'err_msg'  => 'no read-only relocations (fwknop client)',
251         'function' => \&read_only_relocations,
252         'binary'   => $fwknopCmd,
253         'fatal'    => $NO
254     },
255     {
256         'category' => 'build security',
257         'subcategory' => 'client',
258         'detail'   => 'immediate binding',
259         'err_msg'  => 'no immediate binding (fwknop client)',
260         'function' => \&immediate_binding,
261         'binary'   => $fwknopCmd,
262         'fatal'    => $NO
263     },
264
265     {
266         'category' => 'build',
267         'subcategory' => 'server',
268         'detail'   => 'binary exists',
269         'err_msg'  => 'binary not found',
270         'function' => \&binary_exists,
271         'binary'   => $fwknopdCmd,
272         'fatal'    => $YES
273     },
274
275     {
276         'category' => 'build security',
277         'subcategory' => 'server',
278         'detail'   => 'Position Independent Executable (PIE)',
279         'err_msg'  => 'non PIE binary (fwknopd server)',
280         'function' => \&pie_binary,
281         'binary'   => $fwknopdCmd,
282         'fatal'    => $NO
283     },
284     {
285         'category' => 'build security',
286         'subcategory' => 'server',
287         'detail'   => 'stack protected binary',
288         'err_msg'  => 'non stack protected binary (fwknopd server)',
289         'function' => \&stack_protected_binary,
290         'binary'   => $fwknopdCmd,
291         'fatal'    => $NO
292     },
293     {
294         'category' => 'build security',
295         'subcategory' => 'server',
296         'detail'   => 'fortify source functions',
297         'err_msg'  => 'source functions not fortified (fwknopd server)',
298         'function' => \&fortify_source_functions,
299         'binary'   => $fwknopdCmd,
300         'fatal'    => $NO
301     },
302     {
303         'category' => 'build security',
304         'subcategory' => 'server',
305         'detail'   => 'read-only relocations',
306         'err_msg'  => 'no read-only relocations (fwknopd server)',
307         'function' => \&read_only_relocations,
308         'binary'   => $fwknopdCmd,
309         'fatal'    => $NO
310     },
311     {
312         'category' => 'build security',
313         'subcategory' => 'server',
314         'detail'   => 'immediate binding',
315         'err_msg'  => 'no immediate binding (fwknopd server)',
316         'function' => \&immediate_binding,
317         'binary'   => $fwknopdCmd,
318         'fatal'    => $NO
319     },
320
321     {
322         'category' => 'build',
323         'subcategory' => 'libfko',
324         'detail'   => 'binary exists',
325         'err_msg'  => 'binary not found',
326         'function' => \&binary_exists,
327         'binary'   => $libfko_bin,
328         'fatal'    => $YES
329     },
330     {
331         'category' => 'build security',
332         'subcategory' => 'libfko',
333         'detail'   => 'stack protected binary',
334         'err_msg'  => 'non stack protected binary (libfko)',
335         'function' => \&stack_protected_binary,
336         'binary'   => $libfko_bin,
337         'fatal'    => $NO
338     },
339     {
340         'category' => 'build security',
341         'subcategory' => 'libfko',
342         'detail'   => 'fortify source functions',
343         'err_msg'  => 'source functions not fortified (libfko)',
344         'function' => \&fortify_source_functions,
345         'binary'   => $libfko_bin,
346         'fatal'    => $NO
347     },
348     {
349         'category' => 'build security',
350         'subcategory' => 'libfko',
351         'detail'   => 'read-only relocations',
352         'err_msg'  => 'no read-only relocations (libfko)',
353         'function' => \&read_only_relocations,
354         'binary'   => $libfko_bin,
355         'fatal'    => $NO
356     },
357     {
358         'category' => 'build security',
359         'subcategory' => 'libfko',
360         'detail'   => 'immediate binding',
361         'err_msg'  => 'no immediate binding (libfko)',
362         'function' => \&immediate_binding,
363         'binary'   => $libfko_bin,
364         'fatal'    => $NO
365     },
366
367     {
368         'category' => 'preliminaries',
369         'subcategory' => 'client',
370         'detail'   => 'usage info',
371         'err_msg'  => 'could not get usage info',
372         'function' => \&generic_exec,
373         'cmdline'  => "LD_LIBRARY_PATH=$lib_dir $valgrind_str $fwknopCmd -h",
374         'fatal'    => $NO
375     },
376     {
377         'category' => 'preliminaries',
378         'subcategory' => 'client',
379         'detail'   => 'getopt() no such argument',
380         'err_msg'  => 'getopt() allowed non-existant argument',
381         'function' => \&generic_exec,
382         'cmdline'  => "LD_LIBRARY_PATH=$lib_dir $valgrind_str $fwknopCmd --no-such-arg",
383         'exec_err' => $YES,
384         'fatal'    => $NO
385     },
386     {
387         'category' => 'preliminaries',
388         'subcategory' => 'client',
389         'detail'   => '--test mode, packet not sent',
390         'err_msg'  => '--test mode, packet sent?',
391         'function' => \&generic_exec,
392         'positive_output_matches' => [qr/test\smode\senabled/],
393         'cmdline'  => "$default_client_args --test",
394         'fatal'    => $NO
395     },
396
397     {
398         'category' => 'preliminaries',
399         'subcategory' => 'client',
400         'detail'   => 'expected code version',
401         'err_msg'  => 'code version mis-match',
402         'function' => \&expected_code_version,
403         'cmdline'  => "LD_LIBRARY_PATH=$lib_dir $valgrind_str $fwknopCmd --version",
404         'fatal'    => $NO
405     },
406
407     {
408         'category' => 'preliminaries',
409         'subcategory' => 'server',
410         'detail'   => 'usage info',
411         'err_msg'  => 'could not get usage info',
412         'function' => \&generic_exec,
413         'cmdline'  => "LD_LIBRARY_PATH=$lib_dir $valgrind_str $fwknopdCmd -h",
414         'fatal'    => $NO
415     },
416     {
417         'category' => 'preliminaries',
418         'subcategory' => 'server',
419         'detail'   => 'getopt() no such argument',
420         'err_msg'  => 'getopt() allowed non-existant argument',
421         'function' => \&generic_exec,
422         'cmdline'  => "LD_LIBRARY_PATH=$lib_dir $valgrind_str $fwknopdCmd --no-such-arg",
423         'exec_err' => $YES,
424         'fatal'    => $NO
425     },
426
427     {
428         'category' => 'preliminaries',
429         'subcategory' => 'server',
430         'detail'   => 'expected code version',
431         'err_msg'  => 'code version mis-match',
432         'function' => \&expected_code_version,
433         'cmdline'  => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
434             "$fwknopdCmd -c $cf{'def'} -a " .
435             "$cf{'def_access'} --version",
436         'fatal'    => $NO
437     },
438     {
439         'category' => 'preliminaries',
440         'detail'   => 'collecting system specifics',
441         'err_msg'  => 'could not get complete system specs',
442         'function' => \&specs,
443         'binary'   => $fwknopdCmd,
444         'fatal'    => $NO
445     },
446
447     {
448         'category' => 'basic operations',
449         'detail'   => 'dump config',
450         'err_msg'  => 'could not dump configuration',
451         'function' => \&generic_exec,
452         'positive_output_matches' => [qr/SYSLOG_IDENTITY/],
453         'exec_err' => $NO,
454         'cmdline'  => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
455             "$fwknopdCmd -c $cf{'def'} " .
456             "-a $cf{'def_access'} --dump-config",
457         'fatal'    => $NO
458     },
459     {
460         'category' => 'basic operations',
461         'detail'   => 'override config',
462         'err_msg'  => 'could not override configuration',
463         'function' => \&generic_exec,
464         'positive_output_matches' => [qr/ENABLE_PCAP_PROMISC.*\'Y\'/],
465         'exec_err' => $NO,
466         'cmdline'  => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
467             "$fwknopdCmd $default_server_conf_args " .
468             "-O $conf_dir/override_fwknopd.conf --dump-config",
469         'fatal'    => $NO
470     },
471
472     {
473         'category' => 'basic operations',
474         'subcategory' => 'client',
475         'detail'   => '--get-key path validation',
476         'err_msg'  => 'accepted improper --get-key path',
477         'function' => \&generic_exec,
478         'positive_output_matches' => [qr/could\snot\sopen/i],
479         'exec_err' => $YES,
480         'cmdline'  => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
481             "$fwknopCmd -A tcp/22 -s $fake_ip " .
482             "-D $loopback_ip --get-key not/there",
483         'fatal'    => $YES
484     },
485     {
486         'category' => 'basic operations',
487         'subcategory' => 'client',
488         'detail'   => 'require [-s|-R|-a]',
489         'err_msg'  => 'allowed null allow IP',
490         'function' => \&generic_exec,
491         'positive_output_matches' => [qr/must\suse\sone\sof/i],
492         'exec_err' => $YES,
493         'cmdline'  => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
494             "$fwknopCmd -D $loopback_ip",
495         'fatal'    => $NO
496     },
497     {
498         'category' => 'basic operations',
499         'subcategory' => 'client',
500         'detail'   => '--allow-ip <IP> valid IP',
501         'err_msg'  => 'permitted invalid --allow-ip arg',
502         'function' => \&generic_exec,
503         'positive_output_matches' => [qr/Invalid\sallow\sIP\saddress/i],
504         'exec_err' => $YES,
505         'cmdline'  => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
506             "$fwknopCmd -A tcp/22 -a invalidIP -D $loopback_ip",
507         'fatal'    => $NO
508     },
509     {
510         'category' => 'basic operations',
511         'subcategory' => 'client',
512         'detail'   => '-A <proto>/<port> specification (proto)',
513         'err_msg'  => 'permitted invalid -A <proto>/<port>',
514         'function' => \&generic_exec,
515         'positive_output_matches' => [qr/Invalid\sSPA\saccess\smessage/i],
516         'exec_err' => $YES,
517         'cmdline'  => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
518             "$fwknopCmd -A invalid/22 -a $fake_ip -D $loopback_ip",
519         'fatal'    => $NO
520     },
521     {
522         'category' => 'basic operations',
523         'subcategory' => 'client',
524         'detail'   => '-A <proto>/<port> specification (port)',
525         'err_msg'  => 'permitted invalid -A <proto>/<port>',
526         'function' => \&generic_exec,
527         'positive_output_matches' => [qr/Invalid\sSPA\saccess\smessage/i],
528         'exec_err' => $YES,
529         'cmdline'  => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
530             "$fwknopCmd -A tcp/600001 -a $fake_ip -D $loopback_ip",
531         'fatal'    => $NO
532     },
533
534     {
535         'category' => 'basic operations',
536         'subcategory' => 'client',
537         'detail'   => 'generate SPA packet',
538         'err_msg'  => 'could not generate SPA packet',
539         'function' => \&client_send_spa_packet,
540         'cmdline'  => $default_client_args,
541         'fatal'    => $YES
542     },
543
544     {
545         'category' => 'basic operations',
546         'subcategory' => 'server',
547         'detail'   => 'list current fwknopd fw rules',
548         'err_msg'  => 'could not list current fwknopd fw rules',
549         'function' => \&generic_exec,
550         'cmdline'  => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
551             "$fwknopdCmd $default_server_conf_args --fw-list",
552         'fatal'    => $NO
553     },
554     {
555         'category' => 'basic operations',
556         'subcategory' => 'server',
557         'detail'   => 'list all current fw rules',
558         'err_msg'  => 'could not list all current fw rules',
559         'function' => \&generic_exec,
560         'cmdline'  => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
561             "$fwknopdCmd $default_server_conf_args --fw-list-all",
562         'fatal'    => $NO
563     },
564     {
565         'category' => 'basic operations',
566         'subcategory' => 'server',
567         'detail'   => 'flush current firewall rules',
568         'err_msg'  => 'could not flush current fw rules',
569         'function' => \&generic_exec,
570         'cmdline'  => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
571             "$fwknopdCmd $default_server_conf_args --fw-flush",
572         'fatal'    => $NO
573     },
574
575     {
576         'category' => 'basic operations',
577         'subcategory' => 'server',
578         'detail'   => 'start',
579         'err_msg'  => 'start error',
580         'function' => \&server_start,
581         'fwknopd_cmdline'  => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
582             "$fwknopdCmd $default_server_conf_args $intf_str",
583         'fatal'    => $NO
584     },
585     {
586         'category' => 'basic operations',
587         'subcategory' => 'server',
588         'detail'   => 'stop',
589         'err_msg'  => 'stop error',
590         'function' => \&server_stop,
591         'fwknopd_cmdline'  => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
592             "$fwknopdCmd $default_server_conf_args $intf_str",
593         'fatal'    => $NO
594     },
595     {
596         'category' => 'basic operations',
597         'subcategory' => 'server',
598         'detail'   => 'write PID',
599         'err_msg'  => 'did not write PID',
600         'function' => \&write_pid,
601         'fwknopd_cmdline'  => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
602             "$fwknopdCmd $default_server_conf_args $intf_str",
603         'fatal'    => $NO
604     },
605
606     {
607         'category' => 'basic operations',
608         'subcategory' => 'server',
609         'detail'   => '--packet-limit 1 exit',
610         'err_msg'  => 'did not exit after one packet',
611         'function' => \&server_packet_limit,
612         'fwknopd_cmdline'  => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
613             "$fwknopdCmd $default_server_conf_args --packet-limit 1 $intf_str",
614         'fatal'    => $NO
615     },
616     {
617         'category' => 'basic operations',
618         'subcategory' => 'server',
619         'detail'   => 'ignore packets < min SPA len (140)',
620         'err_msg'  => 'did not ignore small packets',
621         'function' => \&server_ignore_small_packets,
622         'fwknopd_cmdline'  => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
623             "$fwknopdCmd $default_server_conf_args --packet-limit 1 $intf_str",
624         'fatal'    => $NO
625     },
626     {
627         'category' => 'basic operations',
628         'subcategory' => 'server',
629         'detail'   => '-P bpf filter ignore packet',
630         'err_msg'  => 'filter did not ignore packet',
631         'function' => \&server_bpf_ignore_packet,
632         'cmdline'  => $default_client_args,
633         'fwknopd_cmdline'  => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
634             "$fwknopdCmd $default_server_conf_args --packet-limit 1 $intf_str " .
635             qq|-P "udp port $non_std_spa_port"|,
636         'fatal'    => $NO
637     },
638
639     {
640         'category' => 'Rijndael SPA',
641         'subcategory' => 'client+server',
642         'detail'   => 'complete cycle (tcp/22 ssh)',
643         'err_msg'  => 'could not complete SPA cycle',
644         'function' => \&spa_cycle,
645         'cmdline'  => $default_client_args,
646         'fwknopd_cmdline'  => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
647             "$fwknopdCmd $default_server_conf_args $intf_str",
648         'fw_rule_created' => $NEW_RULE_REQUIRED,
649         'fw_rule_removed' => $NEW_RULE_REMOVED,
650         'fatal'    => $NO
651     },
652     {
653         'category' => 'Rijndael SPA',
654         'subcategory' => 'client+server',
655         'detail'   => 'client IP resolve (tcp/22 ssh)',
656         'err_msg'  => 'could not complete SPA cycle',
657         'function' => \&spa_cycle,
658         'cmdline'  => $client_ip_resolve_args,
659         'no_ip_check' => 1,
660         'fwknopd_cmdline'  => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
661             "$fwknopdCmd $default_server_conf_args $intf_str",
662         'fw_rule_created' => $NEW_RULE_REQUIRED,
663         'fw_rule_removed' => $NEW_RULE_REMOVED,
664         'fatal'    => $NO
665     },
666
667     {
668         'category' => 'Rijndael SPA',
669         'subcategory' => 'client+server',
670         'detail'   => 'dual usage access key (tcp/80 http)',
671         'err_msg'  => 'could not complete SPA cycle',
672         'function' => \&spa_cycle,
673         'cmdline'  => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
674             "$fwknopCmd -A tcp/80 -a $fake_ip -D $loopback_ip --get-key " .
675             "$local_key_file --verbose --verbose",
676         'fwknopd_cmdline'  => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
677             "$fwknopdCmd -c $cf{'def'} -a $cf{'dual_key_access'} " .
678             "-d $default_digest_file -p $default_pid_file $intf_str",
679         ### check for the first stanza that does not allow tcp/80 - the
680         ### second stanza allows this
681         'server_positive_output_matches' => [qr/stanza #1\)\sOne\sor\smore\srequested\sprotocol\/ports\swas\sdenied/],
682         'fw_rule_created' => $NEW_RULE_REQUIRED,
683         'fw_rule_removed' => $NEW_RULE_REMOVED,
684         'fatal'    => $NO
685     },
686     {
687         'category' => 'Rijndael SPA',
688         'subcategory' => 'client+server',
689         'detail'   => 'packet aging (past) (tcp/22 ssh)',
690         'err_msg'  => 'old SPA packet accepted',
691         'function' => \&spa_cycle,
692         'cmdline'  => "$default_client_args --time-offset-minus 300s",
693         'fwknopd_cmdline'  => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
694             "$fwknopdCmd $default_server_conf_args $intf_str",
695         'server_positive_output_matches' => [qr/SPA\sdata\stime\sdifference/],
696         'fw_rule_created' => $REQUIRE_NO_NEW_RULE,
697         'fatal'    => $NO
698     },
699     {
700         'category' => 'Rijndael SPA',
701         'subcategory' => 'client+server',
702         'detail'   => 'packet aging (future) (tcp/22 ssh)',
703         'err_msg'  => 'future SPA packet accepted',
704         'function' => \&spa_cycle,
705         'cmdline'  => "$default_client_args --time-offset-plus 300s",
706         'fwknopd_cmdline'  => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
707             "$fwknopdCmd $default_server_conf_args $intf_str",
708         'server_positive_output_matches' => [qr/SPA\sdata\stime\sdifference/],
709         'fw_rule_created' => $REQUIRE_NO_NEW_RULE,
710         'fatal'    => $NO
711     },
712     {
713         'category' => 'Rijndael SPA',
714         'subcategory' => 'client+server',
715         'detail'   => 'expired stanza (tcp/22 ssh)',
716         'err_msg'  => 'SPA packet accepted',
717         'function' => \&spa_cycle,
718         'cmdline'  => $default_client_args,
719         'fwknopd_cmdline'  => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
720             "$fwknopdCmd -c $cf{'def'} -a $cf{'exp_access'} " .
721             "-d $default_digest_file -p $default_pid_file $intf_str",
722         'server_positive_output_matches' => [qr/Access\sstanza\shas\sexpired/],
723         'fw_rule_created' => $REQUIRE_NO_NEW_RULE,
724         'fatal'    => $NO
725     },
726     {
727         'category' => 'Rijndael SPA',
728         'subcategory' => 'client+server',
729         'detail'   => 'invalid expire date (tcp/22 ssh)',
730         'err_msg'  => 'SPA packet accepted',
731         'function' => \&spa_cycle,
732         'cmdline'  => $default_client_args,
733         'fwknopd_cmdline'  => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
734             "$fwknopdCmd -c $cf{'def'} -a $cf{'invalid_exp_access'} " .
735             "-d $default_digest_file -p $default_pid_file $intf_str",
736         'server_positive_output_matches' => [qr/invalid\sdate\svalue/],
737         'fw_rule_created' => $REQUIRE_NO_NEW_RULE,
738         'fatal'    => $NO
739     },
740     {
741         'category' => 'Rijndael SPA',
742         'subcategory' => 'client+server',
743         'detail'   => 'expired epoch stanza (tcp/22 ssh)',
744         'err_msg'  => 'SPA packet accepted',
745         'function' => \&spa_cycle,
746         'cmdline'  => $default_client_args,
747         'fwknopd_cmdline'  => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
748             "$fwknopdCmd -c $cf{'def'} -a $cf{'exp_epoch_access'} " .
749             "-d $default_digest_file -p $default_pid_file $intf_str",
750         'server_positive_output_matches' => [qr/Access\sstanza\shas\sexpired/],
751         'fw_rule_created' => $REQUIRE_NO_NEW_RULE,
752         'fatal'    => $NO
753     },
754     {
755         'category' => 'Rijndael SPA',
756         'subcategory' => 'client+server',
757         'detail'   => 'future expired stanza (tcp/22 ssh)',
758         'err_msg'  => 'SPA packet not accepted',
759         'function' => \&spa_cycle,
760         'cmdline'  => $default_client_args,
761         'fwknopd_cmdline'  => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
762             "$fwknopdCmd -c $cf{'def'} -a $cf{'future_exp_access'} " .
763             "-d $default_digest_file -p $default_pid_file $intf_str",
764         'fw_rule_created' => $NEW_RULE_REQUIRED,
765         'fw_rule_removed' => $NEW_RULE_REMOVED,
766         'fatal'    => $NO
767     },
768
769     {
770         'category' => 'Rijndael SPA',
771         'subcategory' => 'client+server',
772         'detail'   => 'OPEN_PORTS (tcp/22 ssh)',
773         'err_msg'  => "improper OPEN_PORTS result",
774         'function' => \&spa_cycle,
775         'cmdline'  => $default_client_args,
776         'fwknopd_cmdline'  => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
777             "$fwknopdCmd -c $cf{'def'} -a $cf{'open_ports_access'} " .
778             "-d $default_digest_file -p $default_pid_file $intf_str",
779         'fw_rule_created' => $NEW_RULE_REQUIRED,
780         'fw_rule_removed' => $NEW_RULE_REMOVED,
781         'fatal'    => $NO
782     },
783     {
784         'category' => 'Rijndael SPA',
785         'subcategory' => 'client+server',
786         'detail'   => 'OPEN_PORTS mismatch',
787         'err_msg'  => "SPA packet accepted",
788         'function' => \&spa_cycle,
789         'cmdline'  => $default_client_args,
790         'fwknopd_cmdline'  => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
791             "$fwknopdCmd -c $cf{'def'} -a $cf{'open_ports_mismatch'} " .
792             "-d $default_digest_file -p $default_pid_file $intf_str",
793         'server_positive_output_matches' => [qr/One\s+or\s+more\s+requested/],
794         'fw_rule_created' => $REQUIRE_NO_NEW_RULE,
795         'fatal'    => $NO
796     },
797     {
798         'category' => 'Rijndael SPA',
799         'subcategory' => 'client+server',
800         'detail'   => 'require user (tcp/22 ssh)',
801         'err_msg'  => "missed require user criteria",
802         'function' => \&spa_cycle,
803         'cmdline'  => "SPOOF_USER=$spoof_user $default_client_args",
804         'fwknopd_cmdline'  => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
805             "$fwknopdCmd -c $cf{'def'} -a $cf{'require_user_access'} " .
806             "-d $default_digest_file -p $default_pid_file $intf_str",
807         'fw_rule_created' => $NEW_RULE_REQUIRED,
808         'fw_rule_removed' => $NEW_RULE_REMOVED,
809         'fatal'    => $NO
810     },
811     {
812         'category' => 'Rijndael SPA',
813         'subcategory' => 'client+server',
814         'detail'   => 'user mismatch (tcp/22 ssh)',
815         'err_msg'  => "improper user accepted for access",
816         'function' => \&user_mismatch,
817         'function' => \&spa_cycle,
818         'cmdline'  => $default_client_args,
819         'fwknopd_cmdline'  => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
820             "$fwknopdCmd -c $cf{'def'} -a $cf{'user_mismatch_access'} " .
821             "-d $default_digest_file -p $default_pid_file $intf_str",
822         'server_positive_output_matches' => [qr/Username\s+in\s+SPA\s+data/],
823         'fw_rule_created' => $REQUIRE_NO_NEW_RULE,
824         'fatal'    => $NO
825     },
826     {
827         'category' => 'Rijndael SPA',
828         'subcategory' => 'client+server',
829         'detail'   => 'require src (tcp/22 ssh)',
830         'err_msg'  => "fw rule not created",
831         'function' => \&spa_cycle,
832         'cmdline'  => $default_client_args,
833         'fwknopd_cmdline'  => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
834             "$fwknopdCmd -c $cf{'def'} -a $cf{'require_src_access'} " .
835             "-d $default_digest_file -p $default_pid_file $intf_str",
836         'fw_rule_created' => $NEW_RULE_REQUIRED,
837         'fw_rule_removed' => $NEW_RULE_REMOVED,
838         'fatal'    => $NO
839     },
840     {
841         'category' => 'Rijndael SPA',
842         'subcategory' => 'client+server',
843         'detail'   => 'mismatch require src (tcp/22 ssh)',
844         'err_msg'  => "fw rule created",
845         'function' => \&spa_cycle,
846         'cmdline'  => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
847             "$fwknopCmd -A tcp/22 -s -D $loopback_ip --get-key " .
848             "$local_key_file --verbose --verbose",
849         'fwknopd_cmdline'  => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
850             "$fwknopdCmd -c $cf{'def'} -a $cf{'require_src_access'} " .
851             "-d $default_digest_file -p $default_pid_file $intf_str",
852         'server_positive_output_matches' => [qr/Got\s0.0.0.0\swhen\svalid\ssource\sIP/],
853         'fw_rule_created' => $REQUIRE_NO_NEW_RULE,
854         'fatal'    => $NO
855     },
856
857     {
858         'category' => 'Rijndael SPA',
859         'subcategory' => 'client+server',
860         'detail'   => 'IP filtering (tcp/22 ssh)',
861         'err_msg'  => "did not filter $loopback_ip",
862         'function' => \&spa_cycle,
863         'cmdline'  => $default_client_args,
864         'fwknopd_cmdline'  => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
865             "$fwknopdCmd -c $cf{'def'} -a $cf{'no_src_match'} " .
866             "-d $default_digest_file -p $default_pid_file $intf_str",
867         'server_positive_output_matches' => [qr/No\saccess\sdata\sfound/],
868         'fw_rule_created' => $REQUIRE_NO_NEW_RULE,
869         'fatal'    => $NO
870     },
871     {
872         'category' => 'Rijndael SPA',
873         'subcategory' => 'client+server',
874         'detail'   => 'subnet filtering (tcp/22 ssh)',
875         'err_msg'  => "did not filter $loopback_ip",
876         'function' => \&spa_cycle,
877         'cmdline'  => $default_client_args,
878         'fwknopd_cmdline'  => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
879             "$fwknopdCmd -c $cf{'def'} -a $cf{'no_subnet_match'} " .
880             "-d $default_digest_file -p $default_pid_file $intf_str",
881         'server_positive_output_matches' => [qr/No\saccess\sdata\sfound/],
882         'fw_rule_created' => $REQUIRE_NO_NEW_RULE,
883         'fatal'    => $NO
884     },
885     {
886         'category' => 'Rijndael SPA',
887         'subcategory' => 'client+server',
888         'detail'   => 'IP+subnet filtering (tcp/22 ssh)',
889         'err_msg'  => "did not filter $loopback_ip",
890         'function' => \&spa_cycle,
891         'cmdline'  => $default_client_args,
892         'fwknopd_cmdline'  => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
893             "$fwknopdCmd -c $cf{'def'} -a $cf{'no_multi_src'} " .
894             "-d $default_digest_file -p $default_pid_file $intf_str",
895         'server_positive_output_matches' => [qr/No\saccess\sdata\sfound/],
896         'fw_rule_created' => $REQUIRE_NO_NEW_RULE,
897         'fatal'    => $NO
898     },
899     {
900         'category' => 'Rijndael SPA',
901         'subcategory' => 'client+server',
902         'detail'   => 'IP match (tcp/22 ssh)',
903         'err_msg'  => "did not filter $loopback_ip",
904         'function' => \&spa_cycle,
905         'cmdline'  => $default_client_args,
906         'fwknopd_cmdline'  => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
907             "$fwknopdCmd -c $cf{'def'} -a $cf{'ip_src_match'} " .
908             "-d $default_digest_file -p $default_pid_file $intf_str",
909         'fw_rule_created' => $NEW_RULE_REQUIRED,
910         'fw_rule_removed' => $NEW_RULE_REMOVED,
911         'fatal'    => $NO
912     },
913     {
914         'category' => 'Rijndael SPA',
915         'subcategory' => 'client+server',
916         'detail'   => 'subnet match (tcp/22 ssh)',
917         'err_msg'  => "did not filter $loopback_ip",
918         'function' => \&spa_cycle,
919         'cmdline'  => $default_client_args,
920         'fwknopd_cmdline'  => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
921             "$fwknopdCmd -c $cf{'def'} -a $cf{'subnet_src_match'} " .
922             "-d $default_digest_file -p $default_pid_file $intf_str",
923         'fw_rule_created' => $NEW_RULE_REQUIRED,
924         'fw_rule_removed' => $NEW_RULE_REMOVED,
925         'fatal'    => $NO
926     },
927     {
928         'category' => 'Rijndael SPA',
929         'subcategory' => 'client+server',
930         'detail'   => 'multi IP/net match (tcp/22 ssh)',
931         'err_msg'  => "did not filter $loopback_ip",
932         'function' => \&spa_cycle,
933         'cmdline'  => $default_client_args,
934         'fwknopd_cmdline'  => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
935             "$fwknopdCmd -c $cf{'def'} -a $cf{'multi_src_access'} " .
936             "-d $default_digest_file -p $default_pid_file $intf_str",
937         'fw_rule_created' => $NEW_RULE_REQUIRED,
938         'fw_rule_removed' => $NEW_RULE_REMOVED,
939         'fatal'    => $NO
940     },
941     {
942         'category' => 'Rijndael SPA',
943         'subcategory' => 'client+server',
944         'detail'   => 'multi access stanzas (tcp/22 ssh)',
945         'err_msg'  => "could not complete SPA cycle",
946         'function' => \&spa_cycle,
947         'cmdline'  => $default_client_args,
948         'fwknopd_cmdline'  => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
949             "$fwknopdCmd -c $cf{'def'} -a $cf{'multi_stanza_access'} " .
950             "-d $default_digest_file -p $default_pid_file $intf_str",
951         'fw_rule_created' => $NEW_RULE_REQUIRED,
952         'fw_rule_removed' => $NEW_RULE_REMOVED,
953         'fatal'    => $NO
954     },
955     {
956         'category' => 'Rijndael SPA',
957         'subcategory' => 'client+server',
958         'detail'   => 'bad/good key stanzas (tcp/22 ssh)',
959         'err_msg'  => "could not complete SPA cycle",
960         'function' => \&spa_cycle,
961         'cmdline'  => $default_client_args,
962         'fwknopd_cmdline'  => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
963             "$fwknopdCmd -c $cf{'def'} -a $cf{'broken_keys_access'} " .
964             "-d $default_digest_file -p $default_pid_file $intf_str",
965         'fw_rule_created' => $NEW_RULE_REQUIRED,
966         'fw_rule_removed' => $NEW_RULE_REMOVED,
967         'fatal'    => $NO
968     },
969
970     {
971         'category' => 'Rijndael SPA',
972         'subcategory' => 'client+server',
973         'detail'   => "non-enabled NAT (tcp/22 ssh)",
974         'err_msg'  => "SPA packet not filtered",
975         'function' => \&spa_cycle,
976         'cmdline'  => "$default_client_args -N $internal_nat_host:22",
977         'fwknopd_cmdline'  => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
978             "$fwknopdCmd $default_server_conf_args $intf_str",
979         'server_positive_output_matches' => [qr/requested\sNAT\saccess.*not\senabled/i],
980         'server_conf' => $cf{'nat'},
981         'fw_rule_created' => $REQUIRE_NO_NEW_RULE,
982         'fatal'    => $NO
983     },
984     {
985         'category' => 'Rijndael SPA',
986         'subcategory' => 'client+server',
987         'detail'   => "NAT to $internal_nat_host (tcp/22 ssh)",
988         'err_msg'  => "could not complete NAT SPA cycle",
989         'function' => \&spa_cycle,
990         'cmdline'  => "$default_client_args -N $internal_nat_host:22",
991         'fwknopd_cmdline'  => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
992             "$fwknopdCmd -c $cf{'nat'} -a $cf{'open_ports_access'} " .
993             "-d $default_digest_file -p $default_pid_file $intf_str",
994         'server_positive_output_matches' => [qr/to\:$internal_nat_host\:22/i],
995         'fw_rule_created' => $NEW_RULE_REQUIRED,
996         'fw_rule_removed' => $NEW_RULE_REMOVED,
997         'server_conf' => $cf{'nat'},
998         'fatal'    => $NO
999     },
1000     {
1001         'category' => 'Rijndael SPA',
1002         'subcategory' => 'client+server',
1003         'detail'   => "force NAT $force_nat_host (tcp/22 ssh)",
1004         'err_msg'  => "could not complete NAT SPA cycle",
1005         'function' => \&spa_cycle,
1006         'cmdline'  => $default_client_args,
1007         'fwknopd_cmdline'  => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
1008             "$fwknopdCmd -c $cf{'nat'} -a $cf{'force_nat_access'} " .
1009             "-d $default_digest_file -p $default_pid_file $intf_str",
1010         'server_positive_output_matches' => [qr/to\:$force_nat_host\:22/i],
1011         'server_negative_output_matches' => [qr/to\:$internal_nat_host\:22/i],
1012         'fw_rule_created' => $NEW_RULE_REQUIRED,
1013         'fw_rule_removed' => $NEW_RULE_REMOVED,
1014         'server_conf' => $cf{'nat'},
1015         'fatal'    => $NO
1016     },
1017     {
1018         'category' => 'Rijndael SPA',
1019         'subcategory' => 'client+server',
1020         'detail'   => "local NAT $force_nat_host (tcp/22 ssh)",
1021         'err_msg'  => "could not complete NAT SPA cycle",
1022         'function' => \&spa_cycle,
1023         'cmdline'  => "$default_client_args --nat-local",
1024         'fwknopd_cmdline'  => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
1025             "$fwknopdCmd -c $cf{'local_nat'} -a $cf{'force_nat_access'} " .
1026             "-d $default_digest_file -p $default_pid_file $intf_str",
1027         'server_positive_output_matches' => [qr/to\:$force_nat_host\:22/i,
1028             qr/FWKNOP_INPUT.*dport\s22.*\sACCEPT/],
1029         'server_negative_output_matches' => [qr/to\:$internal_nat_host\:22/i],
1030         'fw_rule_created' => $NEW_RULE_REQUIRED,
1031         'fw_rule_removed' => $NEW_RULE_REMOVED,
1032         'server_conf' => $cf{'nat'},
1033         'fatal'    => $NO
1034     },
1035     {
1036         'category' => 'Rijndael SPA',
1037         'subcategory' => 'client+server',
1038         'detail'   => "local NAT non-FORCE_NAT (tcp/22 ssh)",
1039         'err_msg'  => "could not complete NAT SPA cycle",
1040         'function' => \&spa_cycle,
1041         'cmdline'  => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
1042             "$fwknopCmd -A tcp/80 -a $fake_ip -D $loopback_ip --get-key " .
1043             "$local_key_file --verbose --verbose --nat-local --nat-port 22",
1044         'fwknopd_cmdline'  => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
1045             "$fwknopdCmd -c $cf{'local_nat'} -a $cf{'def_access'} " .
1046             "-d $default_digest_file -p $default_pid_file $intf_str",
1047         'server_positive_output_matches' => [qr/to\:$loopback_ip\:22/i,
1048             qr/FWKNOP_INPUT.*dport\s22.*\sACCEPT/],
1049         'server_negative_output_matches' => [qr/to\:$internal_nat_host\:22/i],
1050         'fw_rule_created' => $NEW_RULE_REQUIRED,
1051         'fw_rule_removed' => $NEW_RULE_REMOVED,
1052         'server_conf' => $cf{'nat'},
1053         'fatal'    => $NO
1054     },
1055
1056     {
1057         'category' => 'Rijndael SPA',
1058         'subcategory' => 'client+server',
1059         'detail'   => 'complete cycle (tcp/23 telnet)',
1060         'err_msg'  => 'could not complete SPA cycle',
1061         'function' => \&spa_cycle,
1062         'cmdline'  => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
1063             "$fwknopCmd -A tcp/23 -a $fake_ip -D $loopback_ip --get-key " .
1064             "$local_key_file --verbose --verbose",
1065         'fwknopd_cmdline'  => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
1066             "$fwknopdCmd $default_server_conf_args $intf_str",
1067         'fw_rule_created' => $NEW_RULE_REQUIRED,
1068         'fw_rule_removed' => $NEW_RULE_REMOVED,
1069         'fatal'    => $NO
1070     },
1071     {
1072         'category' => 'Rijndael SPA',
1073         'subcategory' => 'client+server',
1074         'detail'   => 'complete cycle (tcp/9418 git)',
1075         'err_msg'  => 'could not complete SPA cycle',
1076         'function' => \&spa_cycle,
1077         'cmdline'  => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
1078             "$fwknopCmd -A tcp/9418 -a $fake_ip -D $loopback_ip --get-key " .
1079             "$local_key_file --verbose --verbose",
1080         'fwknopd_cmdline'  => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
1081             "$fwknopdCmd $default_server_conf_args $intf_str",
1082         'fw_rule_created' => $NEW_RULE_REQUIRED,
1083         'fw_rule_removed' => $NEW_RULE_REMOVED,
1084         'fatal'    => $NO
1085     },
1086     {
1087         'category' => 'Rijndael SPA',
1088         'subcategory' => 'client+server',
1089         'detail'   => 'complete cycle (tcp/60001)',
1090         'err_msg'  => 'could not complete SPA cycle',
1091         'function' => \&spa_cycle,
1092         'cmdline'  => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
1093             "$fwknopCmd -A tcp/60001 -a $fake_ip -D $loopback_ip --get-key " .
1094             "$local_key_file --verbose --verbose",
1095         'fwknopd_cmdline'  => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
1096             "$fwknopdCmd $default_server_conf_args $intf_str",
1097         'fw_rule_created' => $NEW_RULE_REQUIRED,
1098         'fw_rule_removed' => $NEW_RULE_REMOVED,
1099         'fatal'    => $NO
1100     },
1101     {
1102         'category' => 'Rijndael SPA',
1103         'subcategory' => 'client+server',
1104         'detail'   => 'multi port (tcp/60001,udp/60001)',
1105         'err_msg'  => 'could not complete SPA cycle',
1106         'function' => \&spa_cycle,
1107         'cmdline'  => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
1108             "$fwknopCmd -A tcp/60001,udp/60001 -a $fake_ip -D $loopback_ip --get-key " .
1109             "$local_key_file --verbose --verbose",
1110         'fwknopd_cmdline'  => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
1111             "$fwknopdCmd $default_server_conf_args $intf_str",
1112         'fw_rule_created' => $NEW_RULE_REQUIRED,
1113         'fw_rule_removed' => $NEW_RULE_REMOVED,
1114         'fatal'    => $NO
1115     },
1116     {
1117         'category' => 'Rijndael SPA',
1118         'subcategory' => 'client+server',
1119         'detail'   => 'multi port (tcp/22,udp/53,tcp/1234)',
1120         'err_msg'  => 'could not complete SPA cycle',
1121         'function' => \&spa_cycle,
1122         'cmdline'  => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
1123             "$fwknopCmd -A tcp/22,udp/53,tcp/1234 -a $fake_ip -D $loopback_ip --get-key " .
1124             "$local_key_file --verbose --verbose",
1125         'fwknopd_cmdline'  => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
1126             "$fwknopdCmd $default_server_conf_args $intf_str",
1127         'fw_rule_created' => $NEW_RULE_REQUIRED,
1128         'fw_rule_removed' => $NEW_RULE_REMOVED,
1129         'fatal'    => $NO
1130     },
1131
1132     {
1133         'category' => 'Rijndael SPA',
1134         'subcategory' => 'client+server',
1135         'detail'   => 'complete cycle (udp/53 dns)',
1136         'err_msg'  => 'could not complete SPA cycle',
1137         'function' => \&spa_cycle,
1138         'cmdline'  => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
1139             "$fwknopCmd -A udp/53 -a $fake_ip -D $loopback_ip --get-key " .
1140             "$local_key_file --verbose --verbose",
1141         'fwknopd_cmdline'  => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
1142             "$fwknopdCmd $default_server_conf_args $intf_str",
1143         'fw_rule_created' => $NEW_RULE_REQUIRED,
1144         'fw_rule_removed' => $NEW_RULE_REMOVED,
1145         'fatal'    => $NO
1146     },
1147     {
1148         'category' => 'Rijndael SPA',
1149         'subcategory' => 'client+server',
1150         'detail'   => "-P bpf SPA over port $non_std_spa_port",
1151         'err_msg'  => 'could not complete SPA cycle',
1152         'function' => \&spa_cycle,
1153         'cmdline'  => "$default_client_args --server-port $non_std_spa_port",
1154         'fwknopd_cmdline'  => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
1155             "$fwknopdCmd $default_server_conf_args $intf_str " .
1156             qq|-P "udp port $non_std_spa_port"|,
1157         'server_positive_output_matches' => [qr/PCAP\sfilter.*\s$non_std_spa_port/],
1158         'fw_rule_created' => $NEW_RULE_REQUIRED,
1159         'fw_rule_removed' => $NEW_RULE_REMOVED,
1160         'fatal'    => $NO
1161     },
1162
1163     {
1164         'category' => 'Rijndael SPA',
1165         'subcategory' => 'client+server',
1166         'detail'   => 'random SPA port (tcp/22 ssh)',
1167         'err_msg'  => 'could not complete SPA cycle',
1168         'function' => \&spa_cycle,
1169         'cmdline'  => "$default_client_args -r",
1170         'fwknopd_cmdline'  => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
1171             "$fwknopdCmd $default_server_conf_args $intf_str " .
1172             qq|-P "udp"|,
1173         'fw_rule_created' => $NEW_RULE_REQUIRED,
1174         'fw_rule_removed' => $NEW_RULE_REMOVED,
1175         'fatal'    => $NO
1176     },
1177
1178     {
1179         'category' => 'Rijndael SPA',
1180         'subcategory' => 'client+server',
1181         'detail'   => 'spoof username (tcp/22)',
1182         'err_msg'  => 'could not spoof username',
1183         'function' => \&spoof_username,
1184         'cmdline'  => "SPOOF_USER=$spoof_user LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
1185             "$fwknopCmd -A tcp/22 -a $fake_ip -D $loopback_ip --get-key " .
1186             "$local_key_file --verbose --verbose",
1187         'fwknopd_cmdline'  => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
1188             "$fwknopdCmd $default_server_conf_args $intf_str",
1189         'fatal'    => $NO
1190     },
1191
1192     {
1193         'category' => 'Rijndael SPA',
1194         'subcategory' => 'client+server',
1195         'detail'   => 'replay attack detection',
1196         'err_msg'  => 'could not detect replay attack',
1197         'function' => \&replay_detection,
1198         'cmdline'  => $default_client_args,
1199         'fwknopd_cmdline'  => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
1200             "$fwknopdCmd $default_server_conf_args $intf_str",
1201         'replay_positive_output_matches' => [qr/Replay\sdetected\sfrom\ssource\sIP/],
1202         'fatal'    => $NO
1203     },
1204     {
1205         'category' => 'Rijndael SPA',
1206         'subcategory' => 'client+server',
1207         'detail'   => 'replay detection (Rijndael prefix)',
1208         'err_msg'  => 'could not detect replay attack',
1209         'function' => \&replay_detection,
1210         'pkt_prefix' => 'U2FsdGVkX1',
1211         'cmdline'  => $default_client_args,
1212         'fwknopd_cmdline'  => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
1213             "$fwknopdCmd $default_server_conf_args $intf_str",
1214         'replay_positive_output_matches' => [qr/Data\sis\snot\sa\svalid\sSPA\smessage\sformat/],
1215         'fatal'    => $NO
1216     },
1217
1218     ### fuzzing tests
1219     {
1220         'category' => 'Rijndael SPA',
1221         'subcategory' => 'FUZZING',
1222         'detail'   => 'overly long port value',
1223         'err_msg'  => 'server crashed or did not detect error condition',
1224         'function' => \&overly_long_port,
1225         'fwknopd_cmdline'  => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
1226             "$fwknopdCmd -c $cf{'disable_aging'} -a $cf{'def_access'} " .
1227             "-d $default_digest_file -p $default_pid_file $intf_str",
1228         'fatal'    => $NO
1229     },
1230     {
1231         'category' => 'Rijndael SPA',
1232         'subcategory' => 'FUZZING',
1233         'detail'   => 'overly long proto value',
1234         'err_msg'  => 'server crashed or did not detect error condition',
1235         'function' => \&overly_long_proto,
1236         'fwknopd_cmdline'  => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
1237             "$fwknopdCmd -c $cf{'disable_aging'} -a $cf{'def_access'} " .
1238             "-d $default_digest_file -p $default_pid_file $intf_str",
1239         'fatal'    => $NO
1240     },
1241     {
1242         'category' => 'Rijndael SPA',
1243         'subcategory' => 'FUZZING',
1244         'detail'   => 'negative port value',
1245         'err_msg'  => 'server crashed or did not detect error condition',
1246         'function' => \&negative_port,
1247         'fwknopd_cmdline'  => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
1248             "$fwknopdCmd -c $cf{'disable_aging'} -a $cf{'def_access'} " .
1249             "-d $default_digest_file -p $default_pid_file $intf_str",
1250         'fatal'    => $NO
1251     },
1252     {
1253         'category' => 'Rijndael SPA',
1254         'subcategory' => 'FUZZING',
1255         'detail'   => 'null port value',
1256         'err_msg'  => 'server crashed or did not detect error condition',
1257         'function' => \&null_port,
1258         'fwknopd_cmdline'  => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
1259             "$fwknopdCmd -c $cf{'disable_aging'} -a $cf{'def_access'} " .
1260             "-d $default_digest_file -p $default_pid_file $intf_str",
1261         'fatal'    => $NO
1262     },
1263     {
1264         'category' => 'Rijndael SPA',
1265         'subcategory' => 'FUZZING',
1266         'detail'   => 'null proto value',
1267         'err_msg'  => 'server crashed or did not detect error condition',
1268         'function' => \&null_proto,
1269         'fwknopd_cmdline'  => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
1270             "$fwknopdCmd -c $cf{'disable_aging'} -a $cf{'def_access'} " .
1271             "-d $default_digest_file -p $default_pid_file $intf_str",
1272         'fatal'    => $NO
1273     },
1274
1275     {
1276         'category' => 'Rijndael SPA',
1277         'subcategory' => 'server',
1278         'detail'   => 'digest cache structure',
1279         'err_msg'  => 'improper digest cache structure',
1280         'function' => \&digest_cache_structure,
1281         'fatal'    => $NO
1282     },
1283
1284     {
1285         'category' => 'Rijndael SPA',
1286         'subcategory' => 'server',
1287         'detail'   => 'ipfw active/expire sets not equal',
1288         'err_msg'  => 'allowed active/expire sets to be the same',
1289         'function' => \&spa_cycle,
1290         'cmdline'  => $default_client_args,
1291         'fwknopd_cmdline'  => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
1292             "$fwknopdCmd -c $cf{'ipfw_active_expire'} -a $cf{'def_access'} " .
1293             "-d $default_digest_file -p $default_pid_file $intf_str",
1294         'server_positive_output_matches' => [qr/Cannot\sset\sidentical\sipfw\sactive\sand\sexpire\ssets/],
1295         'fw_rule_created' => $REQUIRE_NO_NEW_RULE,
1296         'fatal'    => $NO
1297     },
1298
1299     {
1300         'category' => 'Rijndael SPA',
1301         'subcategory' => 'client+server',
1302         'detail'   => 'non-base64 altered SPA data',
1303         'err_msg'  => 'allowed improper SPA data',
1304         'function' => \&altered_non_base64_spa_data,
1305         'cmdline'  => $default_client_args,
1306         'fwknopd_cmdline'  => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
1307             "$fwknopdCmd $default_server_conf_args $intf_str",
1308         'fatal'    => $NO
1309     },
1310     {
1311         'category' => 'Rijndael SPA',
1312         'subcategory' => 'client+server',
1313         'detail'   => 'base64 altered SPA data',
1314         'err_msg'  => 'allowed improper SPA data',
1315         'function' => \&altered_base64_spa_data,
1316         'cmdline'  => $default_client_args,
1317         'fwknopd_cmdline'  => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
1318             "$fwknopdCmd $default_server_conf_args $intf_str",
1319         'fatal'    => $NO
1320     },
1321     {
1322         'category' => 'Rijndael SPA',
1323         'subcategory' => 'client+server',
1324         'detail'   => 'appended data to SPA pkt',
1325         'err_msg'  => 'allowed improper SPA data',
1326         'function' => \&appended_spa_data,
1327         'cmdline'  => $default_client_args,
1328         'fwknopd_cmdline'  => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
1329             "$fwknopdCmd $default_server_conf_args $intf_str",
1330         'fatal'    => $NO
1331     },
1332     {
1333         'category' => 'Rijndael SPA',
1334         'subcategory' => 'client+server',
1335         'detail'   => 'prepended data to SPA pkt',
1336         'err_msg'  => 'allowed improper SPA data',
1337         'function' => \&prepended_spa_data,
1338         'cmdline'  => $default_client_args,
1339         'fwknopd_cmdline'  => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
1340             "$fwknopdCmd $default_server_conf_args $intf_str",
1341         'fatal'    => $NO
1342     },
1343
1344     {
1345         'category' => 'GPG (no pw) SPA',
1346         'subcategory' => 'client+server',
1347         'detail'   => 'complete cycle (tcp/22 ssh)',
1348         'err_msg'  => 'could not complete SPA cycle',
1349         'function' => \&spa_cycle,
1350         'cmdline'  => "$default_client_gpg_args_no_homedir "
1351             . "--gpg-home-dir $gpg_client_home_dir_no_pw",
1352         'fwknopd_cmdline'  => $default_server_gpg_args_no_pw,
1353         'fw_rule_created' => $NEW_RULE_REQUIRED,
1354         'fw_rule_removed' => $NEW_RULE_REMOVED,
1355         'fatal'    => $NO
1356     },
1357     {
1358         'category' => 'GPG (no pw) SPA',
1359         'subcategory' => 'client+server',
1360         'detail'   => 'multi gpg-IDs (tcp/22 ssh)',
1361         'err_msg'  => 'could not complete SPA cycle',
1362         'function' => \&spa_cycle,
1363         'cmdline'  => "$default_client_gpg_args_no_homedir "
1364             . "--gpg-home-dir $gpg_client_home_dir_no_pw",
1365         'fwknopd_cmdline'  => "LD_LIBRARY_PATH=$lib_dir " .
1366             "$valgrind_str $fwknopdCmd -c $cf{'def'} " .
1367             "-a $cf{'multi_gpg_access'} $intf_str " .
1368             "-d $default_digest_file -p $default_pid_file",
1369         'fw_rule_created' => $NEW_RULE_REQUIRED,
1370         'fw_rule_removed' => $NEW_RULE_REMOVED,
1371         'fatal'    => $NO
1372     },
1373
1374     {
1375         'category' => 'GPG (no pw) SPA',
1376         'subcategory' => 'client+server',
1377         'detail'   => 'complete cycle (tcp/23 telnet)',
1378         'err_msg'  => 'could not complete SPA cycle',
1379         'function' => \&spa_cycle,
1380         'cmdline'  => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
1381             "$fwknopCmd -A tcp/23 -a $fake_ip -D $loopback_ip --get-key " .
1382             "$local_key_file --verbose --verbose " .
1383             "--gpg-recipient-key $gpg_server_key " .
1384             "--gpg-signer-key $gpg_client_key " .
1385             "--gpg-home-dir $gpg_client_home_dir_no_pw",
1386         'fwknopd_cmdline'  => $default_server_gpg_args_no_pw,
1387         'fw_rule_created' => $NEW_RULE_REQUIRED,
1388         'fw_rule_removed' => $NEW_RULE_REMOVED,
1389         'fatal'    => $NO
1390     },
1391     {
1392         'category' => 'GPG (no pw) SPA',
1393         'subcategory' => 'client+server',
1394         'detail'   => 'complete cycle (tcp/9418 git)',
1395         'err_msg'  => 'could not complete SPA cycle',
1396         'function' => \&spa_cycle,
1397         'cmdline'  => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
1398             "$fwknopCmd -A tcp/9418 -a $fake_ip -D $loopback_ip --get-key " .
1399             "$local_key_file --verbose --verbose " .
1400             "--gpg-recipient-key $gpg_server_key " .
1401             "--gpg-signer-key $gpg_client_key " .
1402             "--gpg-home-dir $gpg_client_home_dir_no_pw",
1403         'fwknopd_cmdline'  => $default_server_gpg_args_no_pw,
1404         'fw_rule_created' => $NEW_RULE_REQUIRED,
1405         'fw_rule_removed' => $NEW_RULE_REMOVED,
1406         'fatal'    => $NO
1407     },
1408     {
1409         'category' => 'GPG (no pw) SPA',
1410         'subcategory' => 'client+server',
1411         'detail'   => 'complete cycle (tcp/60001)',
1412         'err_msg'  => 'could not complete SPA cycle',
1413         'function' => \&spa_cycle,
1414         'cmdline'  => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
1415             "$fwknopCmd -A tcp/60001 -a $fake_ip -D $loopback_ip --get-key " .
1416             "$local_key_file --verbose --verbose " .
1417             "--gpg-recipient-key $gpg_server_key " .
1418             "--gpg-signer-key $gpg_client_key " .
1419             "--gpg-home-dir $gpg_client_home_dir_no_pw",
1420         'fwknopd_cmdline'  => $default_server_gpg_args_no_pw,
1421         'fw_rule_created' => $NEW_RULE_REQUIRED,
1422         'fw_rule_removed' => $NEW_RULE_REMOVED,
1423         'fatal'    => $NO
1424     },
1425
1426     {
1427         'category' => 'GPG (no pw) SPA',
1428         'subcategory' => 'client+server',
1429         'detail'   => 'complete cycle (udp/53 dns)',
1430         'err_msg'  => 'could not complete SPA cycle',
1431         'function' => \&spa_cycle,
1432         'cmdline'  => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
1433             "$fwknopCmd -A udp/53 -a $fake_ip -D $loopback_ip --get-key " .
1434             "$local_key_file --verbose --verbose " .
1435             "--gpg-recipient-key $gpg_server_key " .
1436             "--gpg-signer-key $gpg_client_key " .
1437             "--gpg-home-dir $gpg_client_home_dir_no_pw",
1438         'fwknopd_cmdline'  => $default_server_gpg_args_no_pw,
1439         'fw_rule_created' => $NEW_RULE_REQUIRED,
1440         'fw_rule_removed' => $NEW_RULE_REMOVED,
1441         'fatal'    => $NO
1442     },
1443
1444     {
1445         'category' => 'GPG (no pw) SPA',
1446         'subcategory' => 'client+server',
1447         'detail'   => 'replay attack detection',
1448         'err_msg'  => 'could not detect replay attack',
1449         'function' => \&replay_detection,
1450         'cmdline'  => "$default_client_gpg_args_no_homedir "
1451             . "--gpg-home-dir $gpg_client_home_dir_no_pw",
1452         'fwknopd_cmdline'  => $default_server_gpg_args_no_pw,
1453         'replay_positive_output_matches' => [qr/Replay\sdetected\sfrom\ssource\sIP/],
1454         'fatal'    => $NO
1455     },
1456     {
1457         'category' => 'GPG (no pw) SPA',
1458         'subcategory' => 'client+server',
1459         'detail'   => 'replay detection (GnuPG prefix)',
1460         'err_msg'  => 'could not detect replay attack',
1461         'function' => \&replay_detection,
1462         'pkt_prefix' => 'hQ',
1463         'cmdline'  => "$default_client_gpg_args_no_homedir "
1464             . "--gpg-home-dir $gpg_client_home_dir_no_pw",
1465         'fwknopd_cmdline'  => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
1466             "$fwknopdCmd $default_server_conf_args $intf_str",
1467         'replay_positive_output_matches' => [qr/Data\sis\snot\sa\svalid\sSPA\smessage\sformat/],
1468         'fatal'    => $NO
1469     },
1470
1471     {
1472         'category' => 'GPG (no pw) SPA',
1473         'subcategory' => 'client+server',
1474         'detail'   => 'non-base64 altered SPA data',
1475         'err_msg'  => 'allowed improper SPA data',
1476         'function' => \&altered_non_base64_spa_data,
1477         'cmdline'  => "$default_client_gpg_args_no_homedir "
1478             . "--gpg-home-dir $gpg_client_home_dir_no_pw",
1479         'fwknopd_cmdline'  => $default_server_gpg_args_no_pw,
1480         'fatal'    => $NO
1481     },
1482     {
1483         'category' => 'GPG (no pw) SPA',
1484         'subcategory' => 'client+server',
1485         'detail'   => 'base64 altered SPA data',
1486         'err_msg'  => 'allowed improper SPA data',
1487         'function' => \&altered_base64_spa_data,
1488         'cmdline'  => "$default_client_gpg_args_no_homedir "
1489             . "--gpg-home-dir $gpg_client_home_dir_no_pw",
1490         'fwknopd_cmdline'  => $default_server_gpg_args_no_pw,
1491         'fatal'    => $NO
1492     },
1493     {
1494         'category' => 'GPG (no pw) SPA',
1495         'subcategory' => 'client+server',
1496         'detail'   => 'appended data to SPA pkt',
1497         'err_msg'  => 'allowed improper SPA data',
1498         'function' => \&appended_spa_data,
1499         'cmdline'  => "$default_client_gpg_args_no_homedir "
1500             . "--gpg-home-dir $gpg_client_home_dir_no_pw",
1501         'fwknopd_cmdline'  => $default_server_gpg_args_no_pw,
1502         'fatal'    => $NO
1503     },
1504     {
1505         'category' => 'GPG (no pw) SPA',
1506         'subcategory' => 'client+server',
1507         'detail'   => 'prepended data to SPA pkt',
1508         'err_msg'  => 'allowed improper SPA data',
1509         'function' => \&prepended_spa_data,
1510         'cmdline'  => "$default_client_gpg_args_no_homedir "
1511             . "--gpg-home-dir $gpg_client_home_dir_no_pw",
1512         'fwknopd_cmdline'  => $default_server_gpg_args_no_pw,
1513         'fatal'    => $NO
1514     },
1515     {
1516         'category' => 'GPG (no pw) SPA',
1517         'subcategory' => 'client+server',
1518         'detail'   => 'spoof username (tcp/22 ssh)',
1519         'err_msg'  => 'could not spoof username',
1520         'function' => \&spoof_username,
1521         'cmdline'  => "SPOOF_USER=$spoof_user $default_client_gpg_args_no_homedir "
1522             . "--gpg-home-dir $gpg_client_home_dir_no_pw",
1523         'fwknopd_cmdline'  => $default_server_gpg_args_no_pw,
1524         'fatal'    => $NO
1525     },
1526
1527     {
1528         'category' => 'GnuPG (GPG) SPA',
1529         'subcategory' => 'client+server',
1530         'detail'   => 'complete cycle (tcp/22 ssh)',
1531         'err_msg'  => 'could not complete SPA cycle',
1532         'function' => \&spa_cycle,
1533         'cmdline'  => $default_client_gpg_args,
1534         'fwknopd_cmdline'  => $default_server_gpg_args,
1535         'fw_rule_created' => $NEW_RULE_REQUIRED,
1536         'fw_rule_removed' => $NEW_RULE_REMOVED,
1537         'fatal'    => $NO
1538     },
1539     {
1540         'category' => 'GnuPG (GPG) SPA',
1541         'subcategory' => 'client+server',
1542         'detail'   => 'multi gpg-IDs (tcp/22 ssh)',
1543         'err_msg'  => 'could not complete SPA cycle',
1544         'function' => \&spa_cycle,
1545         'cmdline'  => $default_client_gpg_args,
1546         'fwknopd_cmdline'  => "LD_LIBRARY_PATH=$lib_dir " .
1547             "$valgrind_str $fwknopdCmd -c $cf{'def'} " .
1548             "-a $cf{'multi_gpg_access'} $intf_str " .
1549             "-d $default_digest_file -p $default_pid_file",
1550         'fw_rule_created' => $NEW_RULE_REQUIRED,
1551         'fw_rule_removed' => $NEW_RULE_REMOVED,
1552         'fatal'    => $NO
1553     },
1554
1555     {
1556         'category' => 'GnuPG (GPG) SPA',
1557         'subcategory' => 'client+server',
1558         'detail'   => 'complete cycle (tcp/23 telnet)',
1559         'err_msg'  => 'could not complete SPA cycle',
1560         'function' => \&spa_cycle,
1561         'cmdline'  => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
1562             "$fwknopCmd -A tcp/23 -a $fake_ip -D $loopback_ip --get-key " .
1563             "$local_key_file --verbose --verbose " .
1564             "--gpg-recipient-key $gpg_server_key " .
1565             "--gpg-signer-key $gpg_client_key " .
1566             "--gpg-home-dir $gpg_client_home_dir",
1567         'fwknopd_cmdline'  => $default_server_gpg_args,
1568         'fw_rule_created' => $NEW_RULE_REQUIRED,
1569         'fw_rule_removed' => $NEW_RULE_REMOVED,
1570         'fatal'    => $NO
1571     },
1572     {
1573         'category' => 'GnuPG (GPG) SPA',
1574         'subcategory' => 'client+server',
1575         'detail'   => 'complete cycle (tcp/9418 git)',
1576         'err_msg'  => 'could not complete SPA cycle',
1577         'function' => \&spa_cycle,
1578         'cmdline'  => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
1579             "$fwknopCmd -A tcp/9418 -a $fake_ip -D $loopback_ip --get-key " .
1580             "$local_key_file --verbose --verbose " .
1581             "--gpg-recipient-key $gpg_server_key " .
1582             "--gpg-signer-key $gpg_client_key " .
1583             "--gpg-home-dir $gpg_client_home_dir",
1584         'fwknopd_cmdline'  => $default_server_gpg_args,
1585         'fw_rule_created' => $NEW_RULE_REQUIRED,
1586         'fw_rule_removed' => $NEW_RULE_REMOVED,
1587         'fatal'    => $NO
1588     },
1589     {
1590         'category' => 'GnuPG (GPG) SPA',
1591         'subcategory' => 'client+server',
1592         'detail'   => 'complete cycle (tcp/60001)',
1593         'err_msg'  => 'could not complete SPA cycle',
1594         'function' => \&spa_cycle,
1595         'cmdline'  => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
1596             "$fwknopCmd -A tcp/60001 -a $fake_ip -D $loopback_ip --get-key " .
1597             "$local_key_file --verbose --verbose " .
1598             "--gpg-recipient-key $gpg_server_key " .
1599             "--gpg-signer-key $gpg_client_key " .
1600             "--gpg-home-dir $gpg_client_home_dir",
1601         'fwknopd_cmdline'  => $default_server_gpg_args,
1602         'fw_rule_created' => $NEW_RULE_REQUIRED,
1603         'fw_rule_removed' => $NEW_RULE_REMOVED,
1604         'fatal'    => $NO
1605     },
1606
1607     {
1608         'category' => 'GnuPG (GPG) SPA',
1609         'subcategory' => 'client+server',
1610         'detail'   => 'complete cycle (udp/53 dns)',
1611         'err_msg'  => 'could not complete SPA cycle',
1612         'function' => \&spa_cycle,
1613         'cmdline'  => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
1614             "$fwknopCmd -A udp/53 -a $fake_ip -D $loopback_ip --get-key " .
1615             "$local_key_file --verbose --verbose " .
1616             "--gpg-recipient-key $gpg_server_key " .
1617             "--gpg-signer-key $gpg_client_key " .
1618             "--gpg-home-dir $gpg_client_home_dir",
1619         'fwknopd_cmdline'  => $default_server_gpg_args,
1620         'fw_rule_created' => $NEW_RULE_REQUIRED,
1621         'fw_rule_removed' => $NEW_RULE_REMOVED,
1622         'fatal'    => $NO
1623     },
1624
1625     {
1626         'category' => 'GnuPG (GPG) SPA',
1627         'subcategory' => 'client+server',
1628         'detail'   => 'replay attack detection',
1629         'err_msg'  => 'could not detect replay attack',
1630         'function' => \&replay_detection,
1631         'cmdline'  => $default_client_gpg_args,
1632         'fwknopd_cmdline'  => $default_server_gpg_args,
1633         'replay_positive_output_matches' => [qr/Replay\sdetected\sfrom\ssource\sIP/],
1634         'fatal'    => $NO
1635     },
1636     {
1637         'category' => 'GnuPG (GPG) SPA',
1638         'subcategory' => 'client+server',
1639         'detail'   => 'replay detection (GnuPG prefix)',
1640         'err_msg'  => 'could not detect replay attack',
1641         'function' => \&replay_detection,
1642         'pkt_prefix' => 'hQ',
1643         'cmdline'  => $default_client_gpg_args,
1644         'fwknopd_cmdline'  => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
1645             "$fwknopdCmd $default_server_conf_args $intf_str",
1646         'replay_positive_output_matches' => [qr/Data\sis\snot\sa\svalid\sSPA\smessage\sformat/],
1647         'fatal'    => $NO
1648     },
1649
1650     {
1651         'category' => 'GnuPG (GPG) SPA',
1652         'subcategory' => 'client+server',
1653         'detail'   => 'non-base64 altered SPA data',
1654         'err_msg'  => 'allowed improper SPA data',
1655         'function' => \&altered_non_base64_spa_data,
1656         'cmdline'  => $default_client_gpg_args,
1657         'fwknopd_cmdline'  => $default_server_gpg_args,
1658         'fatal'    => $NO
1659     },
1660     {
1661         'category' => 'GnuPG (GPG) SPA',
1662         'subcategory' => 'client+server',
1663         'detail'   => 'base64 altered SPA data',
1664         'err_msg'  => 'allowed improper SPA data',
1665         'function' => \&altered_base64_spa_data,
1666         'cmdline'  => $default_client_gpg_args,
1667         'fwknopd_cmdline'  => $default_server_gpg_args,
1668         'fatal'    => $NO
1669     },
1670     {
1671         'category' => 'GnuPG (GPG) SPA',
1672         'subcategory' => 'client+server',
1673         'detail'   => 'appended data to SPA pkt',
1674         'err_msg'  => 'allowed improper SPA data',
1675         'function' => \&appended_spa_data,
1676         'cmdline'  => $default_client_gpg_args,
1677         'fwknopd_cmdline'  => $default_server_gpg_args,
1678         'fatal'    => $NO
1679     },
1680     {
1681         'category' => 'GnuPG (GPG) SPA',
1682         'subcategory' => 'client+server',
1683         'detail'   => 'prepended data to SPA pkt',
1684         'err_msg'  => 'allowed improper SPA data',
1685         'function' => \&prepended_spa_data,
1686         'cmdline'  => $default_client_gpg_args,
1687         'fwknopd_cmdline'  => $default_server_gpg_args,
1688         'fatal'    => $NO
1689     },
1690     {
1691         'category' => 'GnuPG (GPG) SPA',
1692         'subcategory' => 'client+server',
1693         'detail'   => 'spoof username (tcp/22 ssh)',
1694         'err_msg'  => 'could not spoof username',
1695         'function' => \&spoof_username,
1696         'cmdline'  => "SPOOF_USER=$spoof_user $default_client_gpg_args",
1697         'fwknopd_cmdline'  => $default_server_gpg_args,
1698         'fatal'    => $NO
1699     },
1700     {
1701         'category' => 'GnuPG (GPG) SPA',
1702         'subcategory' => 'server',
1703         'detail'   => 'digest cache structure',
1704         'err_msg'  => 'improper digest cache structure',
1705         'function' => \&digest_cache_structure,
1706         'fatal'    => $NO
1707     },
1708 );
1709
1710 if ($use_valgrind) {
1711     push @tests,
1712         {
1713             'category' => 'valgrind output',
1714             'subcategory' => 'flagged functions',
1715             'detail'   => '',
1716             'err_msg'  => 'could not parse flagged functions',
1717             'function' => \&parse_valgrind_flagged_functions,
1718             'fatal'    => $NO
1719         };
1720 }
1721
1722 my %test_keys = (
1723     'category'        => $REQUIRED,
1724     'subcategory'     => $OPTIONAL,
1725     'detail'          => $REQUIRED,
1726     'function'        => $REQUIRED,
1727     'binary'          => $OPTIONAL,
1728     'cmdline'         => $OPTIONAL,
1729     'fwknopd_cmdline' => $OPTIONAL,
1730     'fatal'           => $OPTIONAL,
1731     'exec_err'        => $OPTIONAL,
1732     'fw_rule_created' => $OPTIONAL,
1733     'fw_rule_removed' => $OPTIONAL,
1734     'server_conf'     => $OPTIONAL,
1735     'pkt_prefix'      => $OPTIONAL,
1736     'no_ip_check'     => $OPTIONAL,
1737     'positive_output_matches' => $OPTIONAL,
1738     'negative_output_matches' => $OPTIONAL,
1739     'server_positive_output_matches' => $OPTIONAL,
1740     'server_negative_output_matches' => $OPTIONAL,
1741     'replay_positive_output_matches' => $OPTIONAL,
1742     'replay_negative_output_matches' => $OPTIONAL,
1743 );
1744
1745 if ($diff_mode) {
1746     &diff_test_results();
1747     exit 0;
1748 }
1749
1750 ### make sure everything looks as expected before continuing
1751 &init();
1752
1753 &logr("\n[+] Starting the fwknop test suite...\n\n" .
1754     "    args: @args_cp\n\n"
1755 );
1756
1757 ### save the results from any previous test suite run
1758 ### so that we can potentially compare them with --diff
1759 if ($saved_last_results) {
1760     &logr("    Saved results from previous run " .
1761         "to: ${output_dir}.last/\n\n");
1762 }
1763
1764 ### main loop through all of the tests
1765 for my $test_hr (@tests) {
1766     &run_test($test_hr);
1767 }
1768
1769 &logr("\n[+] passed/failed/executed: $passed/$failed/$executed tests\n\n");
1770
1771 copy $logfile, "$output_dir/$logfile" or die $!;
1772
1773 exit 0;
1774
1775 #===================== end main =======================
1776
1777 sub run_test() {
1778     my $test_hr = shift;
1779
1780     my $msg = "[$test_hr->{'category'}]";
1781     $msg .= " [$test_hr->{'subcategory'}]" if $test_hr->{'subcategory'};
1782     $msg .= " $test_hr->{'detail'}";
1783
1784     return unless &process_include_exclude($msg);
1785
1786     if ($list_mode) {
1787         print $msg, "\n";
1788         return;
1789     }
1790
1791     &dots_print($msg);
1792
1793     $executed++;
1794     $current_test_file  = "$output_dir/$executed.test";
1795     $server_test_file   = "$output_dir/${executed}_fwknopd.test";
1796
1797     &write_test_file("[+] TEST: $msg\n", $current_test_file);
1798     $test_hr->{'msg'} = $msg;
1799     if (&{$test_hr->{'function'}}($test_hr)) {
1800         &logr("pass ($executed)\n");
1801         $passed++;
1802     } else {
1803         &logr("fail ($executed)\n");
1804         $failed++;
1805
1806         if ($test_hr->{'fatal'} eq $YES) {
1807             die "[*] required test failed, exiting.";
1808         }
1809     }
1810
1811     return;
1812 }
1813
1814 sub process_include_exclude() {
1815     my $msg = shift;
1816
1817     ### inclusions/exclusions
1818     if (@tests_to_include) {
1819         my $found = 0;
1820         for my $test (@tests_to_include) {
1821             if ($msg =~ $test or ($use_valgrind
1822                     and $msg =~ /valgrind\soutput/)) {
1823                 $found = 1;
1824                 last;
1825             }
1826         }
1827         return 0 unless $found;
1828     }
1829     if (@tests_to_exclude) {
1830         my $found = 0;
1831         for my $test (@tests_to_exclude) {
1832             if ($msg =~ $test) {
1833                 $found = 1;
1834                 last;
1835             }
1836         }
1837         return 0 if $found;
1838     }
1839     return 1;
1840 }
1841
1842 sub diff_test_results() {
1843
1844     $diff_dir1 = "${output_dir}.last" unless $diff_dir1;
1845     $diff_dir2 = $output_dir unless $diff_dir2;
1846
1847     die "[*] Need results from a previous run before running --diff"
1848         unless -d $diff_dir2;
1849     die "[*] Current results set does not exist." unless -d $diff_dir1;
1850
1851     my %current_tests  = ();
1852     my %previous_tests = ();
1853
1854     ### Only diff results for matching tests (parse the logfile to see which
1855     ### test numbers match across the two test cycles).
1856     &build_results_hash(\%current_tests, $diff_dir1);
1857     &build_results_hash(\%previous_tests, $diff_dir2);
1858
1859     for my $test_msg (sort {$current_tests{$a}{'num'} <=> $current_tests{$b}{'num'}}
1860                 keys %current_tests) {
1861         my $current_result = $current_tests{$test_msg}{'pass_fail'};
1862         my $current_num    = $current_tests{$test_msg}{'num'};
1863         if (defined $previous_tests{$test_msg}) {
1864             print "[+] Checking: $test_msg\n";
1865             my $previous_result = $previous_tests{$test_msg}{'pass_fail'};
1866             my $previous_num    = $previous_tests{$test_msg}{'num'};
1867             if ($current_result ne $previous_result) {
1868                 print " DIFF: **$current_result** $test_msg\n";
1869             }
1870
1871             &diff_results($previous_num, $current_num);
1872             print "\n";
1873         }
1874     }
1875
1876     exit 0;
1877 }
1878
1879 sub diff_results() {
1880     my ($previous_num, $current_num) = @_;
1881
1882     ### edit out any valgrind "==354==" prefixes
1883     my $valgrind_search_re = qr/^==\d+==\s/;
1884
1885     ### remove CMD timestamps
1886     my $cmd_search_re = qr/^\S+\s.*?\s\d{4}\sCMD\:/;
1887
1888     for my $file ("$diff_dir1/${previous_num}.test",
1889         "$diff_dir1/${previous_num}_fwknopd.test",
1890         "$diff_dir2/${current_num}.test",
1891         "$diff_dir2/${current_num}_fwknopd.test",
1892     ) {
1893         system qq{perl -p -i -e 's|$valgrind_search_re||' $file} if -e $file;
1894         system qq{perl -p -i -e 's|$cmd_search_re|CMD:|' $file} if -e $file;
1895     }
1896
1897     if (-e "$diff_dir1/${previous_num}.test"
1898             and -e "$diff_dir2/${current_num}.test") {
1899         system "diff -u $diff_dir1/${previous_num}.test " .
1900             "$diff_dir2/${current_num}.test";
1901     }
1902
1903     if (-e "$diff_dir1/${previous_num}_fwknopd.test"
1904             and -e "$diff_dir2/${current_num}_fwknopd.test") {
1905         system "diff -u $diff_dir1/${previous_num}_fwknopd.test " .
1906             "$diff_dir2/${current_num}_fwknopd.test";
1907     }
1908
1909     return;
1910 }
1911
1912 sub build_results_hash() {
1913     my ($hr, $dir) = @_;
1914
1915     open F, "< $dir/$logfile" or die $!;
1916     while (<F>) {
1917         if (/^(.*?)\.\.\..*(pass|fail)\s\((\d+)\)/) {
1918             $hr->{$1}{'pass_fail'} = $2;
1919             $hr->{$1}{'num'}       = $3;
1920         }
1921     }
1922     return;
1923 }
1924
1925 sub compile_warnings() {
1926
1927     ### 'make clean' as root
1928     return 0 unless &run_cmd('make -C .. clean',
1929         $cmd_out_tmp, $current_test_file);
1930
1931     if ($sudo_path) {
1932         my $username = getpwuid((stat($configure_path))[4]);
1933         die "[*] Could not determine $configure_path owner"
1934             unless $username;
1935
1936         return 0 unless &run_cmd("$sudo_path -u $username make -C ..",
1937             $cmd_out_tmp, $current_test_file);
1938
1939     } else {
1940
1941         return 0 unless &run_cmd('make -C ..',
1942             $cmd_out_tmp, $current_test_file);
1943
1944     }
1945
1946     ### look for compilation warnings - something like:
1947     ###     warning: ‘test’ is used uninitialized in this function
1948     return 0 if &file_find_regex([qr/\swarning:\s/, qr/gcc\:.*\sunused/],
1949         $MATCH_ANY, $current_test_file);
1950
1951     ### the new binaries should exist
1952     unless (-e $fwknopCmd and -x $fwknopCmd) {
1953         &write_test_file("[-] $fwknopCmd does not exist or not executable.\n",
1954             $current_test_file);
1955     }
1956     unless (-e $fwknopdCmd and -x $fwknopdCmd) {
1957         &write_test_file("[-] $fwknopdCmd does not exist or not executable.\n",
1958             $current_test_file);
1959     }
1960
1961     return 1;
1962 }
1963
1964 sub make_distcheck() {
1965
1966     ### 'make clean' as root
1967     return 0 unless &run_cmd('make -C .. distcheck',
1968         $cmd_out_tmp, $current_test_file);
1969
1970     ### look for compilation warnings - something like:
1971     ###     warning: ‘test’ is used uninitialized in this function
1972     return 1 if &file_find_regex([qr/archives\sready\sfor\sdistribution/],
1973         $MATCH_ALL, $current_test_file);
1974
1975     return 0;
1976 }
1977
1978
1979 sub binary_exists() {
1980     my $test_hr = shift;
1981     return 0 unless $test_hr->{'binary'};
1982
1983     ### account for different libfko.so paths (e.g. libfko.so.0.3 with no
1984     ### libfko.so link on OpenBSD, and libfko.dylib path on Mac OS X)
1985
1986     if ($test_hr->{'binary'} =~ /libfko/) {
1987         unless (-e $test_hr->{'binary'}) {
1988             my $file = "$lib_dir/libfko.dylib";
1989             if (-e $file) {
1990                 $test_hr->{'binary'} = $file;
1991                 $libfko_bin = $file;
1992             } else {
1993                 for my $f (glob("$lib_dir/libfko.so*")) {
1994                     if (-e $f and -x $f) {
1995                         $test_hr->{'binary'} = $f;
1996                         $libfko_bin = $f;
1997                         last;
1998                     }
1999                 }
2000             }
2001         }
2002     }
2003
2004     return 0 unless -e $test_hr->{'binary'} and -x $test_hr->{'binary'};
2005     return 1;
2006 }
2007
2008 sub expected_code_version() {
2009     my $test_hr = shift;
2010
2011     unless (-e '../VERSION') {
2012         &write_test_file("[-] ../VERSION file does not exist.\n",
2013             $current_test_file);
2014         return 0;
2015     }
2016
2017     open F, '< ../VERSION' or die $!;
2018     my $line = <F>;
2019     close F;
2020     if ($line =~ /(\d.*\d)/) {
2021         my $version = $1;
2022         return 0 unless &run_cmd($test_hr->{'cmdline'},
2023             $cmd_out_tmp, $current_test_file);
2024         return 1 if &file_find_regex([qr/$version/],
2025             $MATCH_ALL, $current_test_file);
2026     }
2027     return 0;
2028 }
2029
2030 sub client_send_spa_packet() {
2031     my $test_hr = shift;
2032
2033     &write_key('fwknoptest', $local_key_file);
2034
2035     return 0 unless &run_cmd($test_hr->{'cmdline'},
2036             $cmd_out_tmp, $current_test_file);
2037     return 0 unless &file_find_regex([qr/final\spacked/i],
2038         $MATCH_ALL, $current_test_file);
2039
2040     return 1;
2041 }
2042
2043 sub spa_cycle() {
2044     my $test_hr = shift;
2045
2046     my ($rv, $server_was_stopped, $fw_rule_created, $fw_rule_removed)
2047             = &client_server_interaction($test_hr, [], $USE_CLIENT);
2048
2049     if ($test_hr->{'fw_rule_created'} eq $NEW_RULE_REQUIRED) {
2050         $rv = 0 unless $fw_rule_created;
2051     } elsif ($test_hr->{'fw_rule_created'} eq $REQUIRE_NO_NEW_RULE) {
2052         $rv = 0 if $fw_rule_created;
2053     }
2054
2055     if ($test_hr->{'fw_rule_removed'} eq $NEW_RULE_REMOVED) {
2056         $rv = 0 unless $fw_rule_removed;
2057     } elsif ($test_hr->{'fw_rule_removed'} eq $REQUIRE_NO_NEW_REMOVED) {
2058         $rv = 0 if $fw_rule_removed;
2059     }
2060
2061     if ($test_hr->{'server_positive_output_matches'}) {
2062         $rv = 0 unless &file_find_regex(
2063             $test_hr->{'server_positive_output_matches'},
2064             $MATCH_ALL, $server_test_file);
2065     }
2066
2067     if ($test_hr->{'server_negative_output_matches'}) {
2068         $rv = 0 if &file_find_regex(
2069             $test_hr->{'server_negative_output_matches'},
2070             $MATCH_ANY, $server_test_file);
2071     }
2072
2073     return $rv;
2074 }
2075
2076 sub spoof_username() {
2077     my $test_hr = shift;
2078
2079     my $rv = &spa_cycle($test_hr);
2080
2081     unless (&file_find_regex([qr/Username:\s*$spoof_user/],
2082             $MATCH_ALL, $current_test_file)) {
2083         $rv = 0;
2084     }
2085
2086     unless (&file_find_regex([qr/Username:\s*$spoof_user/],
2087             $MATCH_ALL, $server_test_file)) {
2088         $rv = 0;
2089     }
2090
2091     return $rv;
2092 }
2093
2094 sub replay_detection() {
2095     my $test_hr = shift;
2096
2097     ### do a complete SPA cycle and then parse the SPA packet out of the
2098     ### current test file and re-send
2099
2100     return 0 unless &spa_cycle($test_hr);
2101
2102     my $spa_pkt = &get_spa_packet_from_file($current_test_file);
2103
2104     unless ($spa_pkt) {
2105         &write_test_file("[-] could not get SPA packet " .
2106             "from file: $current_test_file\n",
2107             $current_test_file);
2108         return 0;
2109     }
2110
2111     if ($test_hr->{'pkt_prefix'}) {
2112         $spa_pkt = $test_hr->{'pkt_prefix'} . $spa_pkt;
2113     }
2114
2115     my @packets = (
2116         {
2117             'proto'  => 'udp',
2118             'port'   => $default_spa_port,
2119             'dst_ip' => $loopback_ip,
2120             'data'   => $spa_pkt,
2121         },
2122     );
2123
2124     my ($rv, $server_was_stopped, $fw_rule_created, $fw_rule_removed)
2125         = &client_server_interaction($test_hr, \@packets, $USE_PREDEF_PKTS);
2126
2127     $rv = 0 unless $server_was_stopped;
2128
2129     if ($test_hr->{'replay_positive_output_matches'}) {
2130         $rv = 0 unless &file_find_regex(
2131             $test_hr->{'replay_positive_output_matches'},
2132             $MATCH_ALL, $server_test_file);
2133     }
2134
2135     if ($test_hr->{'replay_negative_output_matches'}) {
2136         $rv = 0 if &file_find_regex(
2137             $test_hr->{'replay_negative_output_matches'},
2138             $MATCH_ANY, $server_test_file);
2139     }
2140
2141     return $rv;
2142 }
2143
2144 sub digest_cache_structure() {
2145     my $test_hr = shift;
2146     my $rv = 1;
2147
2148     &run_cmd("file $default_digest_file", $cmd_out_tmp, $current_test_file);
2149
2150     if (&file_find_regex([qr/ASCII/i], $MATCH_ALL, $cmd_out_tmp)) {
2151
2152         ### the format should be:
2153         ### <digest> <proto> <src_ip> <src_port> <dst_ip> <dst_port> <time>
2154         open F, "< $default_digest_file" or
2155             die "[*] could not open $default_digest_file: $!";
2156         while (<F>) {
2157             next if /^#/;
2158             next unless /\S/;
2159             unless (m|^\S+\s+\d+\s+$ip_re\s+\d+\s+$ip_re\s+\d+\s+\d+|) {
2160                 &write_test_file("[-] invalid digest.cache line: $_",
2161                     $current_test_file);
2162                 $rv = 0;
2163                 last;
2164             }
2165         }
2166         close F;
2167     } elsif (&file_find_regex([qr/dbm/i], $MATCH_ALL, $cmd_out_tmp)) {
2168         &write_test_file("[+] DBM digest file format, " .
2169             "assuming this is valid.\n", $current_test_file);
2170     } else {
2171         ### don't know what kind of file the digest.cache is
2172         &write_test_file("[-] unrecognized file type for " .
2173             "$default_digest_file.\n", $current_test_file);
2174         $rv = 0;
2175     }
2176
2177     if ($rv) {
2178         &write_test_file("[+] valid digest.cache structure.\n",
2179             $current_test_file);
2180     }
2181
2182     return $rv;
2183 }
2184
2185 sub server_bpf_ignore_packet() {
2186     my $test_hr = shift;
2187
2188     my $rv = 1;
2189     my $server_was_stopped = 0;
2190     my $fw_rule_created = 0;
2191     my $fw_rule_removed = 0;
2192
2193     unless (&client_send_spa_packet($test_hr)) {
2194         &write_test_file("[-] fwknop client execution error.\n",
2195             $current_test_file);
2196         $rv = 0;
2197     }
2198
2199     my $spa_pkt = &get_spa_packet_from_file($current_test_file);
2200
2201     unless ($spa_pkt) {
2202         &write_test_file("[-] could not get SPA packet " .
2203             "from file: $current_test_file\n", $current_test_file);
2204         return 0;
2205     }
2206
2207     my @packets = (
2208         {
2209             'proto'  => 'udp',
2210             'port'   => $default_spa_port,
2211             'dst_ip' => $loopback_ip,
2212             'data'   => $spa_pkt,
2213         },
2214     );
2215
2216     ($rv, $server_was_stopped, $fw_rule_created, $fw_rule_removed)
2217         = &client_server_interaction($test_hr, \@packets, $USE_PREDEF_PKTS);
2218
2219     unless (&file_find_regex([qr/PCAP\sfilter.*\s$non_std_spa_port/],
2220             $MATCH_ALL, $server_test_file)) {
2221         $rv = 0;
2222     }
2223
2224     return $rv;
2225 }
2226
2227 sub altered_non_base64_spa_data() {
2228     my $test_hr = shift;
2229
2230     my $rv = 1;
2231     my $server_was_stopped = 0;
2232     my $fw_rule_created = 0;
2233     my $fw_rule_removed = 0;
2234
2235     unless (&client_send_spa_packet($test_hr)) {
2236         &write_test_file("[-] fwknop client execution error.\n",
2237             $current_test_file);
2238         $rv = 0;
2239     }
2240
2241     my $spa_pkt = &get_spa_packet_from_file($current_test_file);
2242
2243     unless ($spa_pkt) {
2244         &write_test_file("[-] could not get SPA packet " .
2245             "from file: $current_test_file\n", $current_test_file);
2246         return 0;
2247     }
2248
2249     ### alter one byte (change to a ":")
2250     $spa_pkt =~ s|^(.{3}).|$1:|;
2251
2252     my @packets = (
2253         {
2254             'proto'  => 'udp',
2255             'port'   => $default_spa_port,
2256             'dst_ip' => $loopback_ip,
2257             'data'   => $spa_pkt,
2258         },
2259     );
2260
2261     ($rv, $server_was_stopped, $fw_rule_created, $fw_rule_removed)
2262         = &client_server_interaction($test_hr, \@packets, $USE_PREDEF_PKTS);
2263
2264     $rv = 0 unless $server_was_stopped;
2265
2266     return $rv;
2267 }
2268
2269 sub null_proto() {
2270     my $test_hr = shift;
2271
2272     my $rv = 1;
2273     my $server_was_stopped = 0;
2274     my $fw_rule_created = 0;
2275     my $fw_rule_removed = 0;
2276
2277     ### this packet was generated with a modified fwknop client via the
2278     ### following command line:
2279     #
2280     # LD_LIBRARY_PATH=../lib/.libs  ../client/.libs/fwknop -A /22 \
2281     # -a 127.0.0.2 -D 127.0.0.1 --get-key local_spa.key \
2282     # --verbose --verbose
2283     #
2284     my $spa_pkt =
2285         '/JT14qxh9P4iy+CuUZahThaQjoEuL2zd46a+jL6sTrBZJSa6faUX4dH5fte/4ZJv+9f' .
2286         'd/diWYKAUvdQ4DydPGlR7mwQa2W+obKpqrsTBz7D4054z6ATAOGpCtifakEVl1XRc2+' .
2287         'hW04WpY8mdUNu9i+PrfPr7/KxqU';
2288
2289     my @packets = (
2290         {
2291             'proto'  => 'udp',
2292             'port'   => $default_spa_port,
2293             'dst_ip' => $loopback_ip,
2294             'data'   => $spa_pkt,
2295         },
2296     );
2297
2298     ($rv, $server_was_stopped, $fw_rule_created, $fw_rule_removed)
2299         = &client_server_interaction($test_hr, \@packets, $USE_PREDEF_PKTS);
2300
2301     $rv = 0 unless $server_was_stopped;
2302
2303     if ($fw_rule_created) {
2304         &write_test_file("[-] new fw rule created.\n", $current_test_file);
2305         $rv = 0;
2306     } else {
2307         &write_test_file("[+] new fw rule not created.\n", $current_test_file);
2308     }
2309
2310     unless (&file_find_regex([qr/Args\scontain\sinvalid\sdata/],
2311             $MATCH_ALL, $server_test_file)) {
2312         $rv = 0;
2313     }
2314
2315     return $rv;
2316 }
2317
2318 sub null_port() {
2319     my $test_hr = shift;
2320
2321     my $rv = 1;
2322     my $server_was_stopped = 0;
2323     my $fw_rule_created = 0;
2324     my $fw_rule_removed = 0;
2325
2326     ### this packet was generated with a modified fwknop client via the
2327     ### following command line:
2328     #
2329     # LD_LIBRARY_PATH=../lib/.libs  ../client/.libs/fwknop -A tcp/ \
2330     # -a 127.0.0.2 -D 127.0.0.1 --get-key local_spa.key \
2331     # --verbose --verbose
2332     #
2333     my $spa_pkt =
2334         '94nu7hvq6V/3A27GzjHwfPnPCQfs44ySlraIFYHOAqy5YqjkrBS67nH35tX55N1BrYZ' .
2335         '07zvcT03keUhLE1Uo7Wme1nE7BfTOG5stmIK1UQI85sL52//lDHu+xCqNcL7GUKbVRz' .
2336         'ekw+EUscVvUkrsRcVtSvOm+fCNo';
2337
2338     my @packets = (
2339         {
2340             'proto'  => 'udp',
2341             'port'   => $default_spa_port,
2342             'dst_ip' => $loopback_ip,
2343             'data'   => $spa_pkt,
2344         },
2345     );
2346
2347     ($rv, $server_was_stopped, $fw_rule_created, $fw_rule_removed)
2348         = &client_server_interaction($test_hr, \@packets, $USE_PREDEF_PKTS);
2349
2350     $rv = 0 unless $server_was_stopped;
2351
2352     if ($fw_rule_created) {
2353         &write_test_file("[-] new fw rule created.\n", $current_test_file);
2354         $rv = 0;
2355     } else {
2356         &write_test_file("[+] new fw rule not created.\n", $current_test_file);
2357     }
2358
2359     unless (&file_find_regex([qr/Args\scontain\sinvalid\sdata/],
2360             $MATCH_ALL, $server_test_file)) {
2361         $rv = 0;
2362     }
2363
2364     return $rv;
2365 }
2366
2367 sub negative_port() {
2368     my $test_hr = shift;
2369
2370     my $rv = 1;
2371     my $server_was_stopped = 0;
2372     my $fw_rule_created = 0;
2373     my $fw_rule_removed = 0;
2374
2375     ### this packet was generated with a modified fwknop client via the
2376     ### following command line:
2377     #
2378     # LD_LIBRARY_PATH=../lib/.libs  ../client/.libs/fwknop -A \
2379     # tcp/-33 -a 127.0.0.2 -D 127.0.0.1 --get-key local_spa.key \
2380     # --verbose --verbose
2381     #
2382     my $spa_pkt =
2383         '/weoc+pEuQknZo8ImWTQBB+/PwSJ2/TcrmFoSkxpRXX4+jlUxoJakHrioxh8rhLmAD9' .
2384         '8E4lMnq+EbM2XYdhs2alpZ5bovAFojMsYRWwr/BvRO4Um4Fmo9z9sY3DR477TXNYXBR' .
2385         'iGXWxSL4u+AWSSePK3qiiYoRQVw';
2386
2387     my @packets = (
2388         {
2389             'proto'  => 'udp',
2390             'port'   => $default_spa_port,
2391             'dst_ip' => $loopback_ip,
2392             'data'   => $spa_pkt,
2393         },
2394     );
2395
2396     ($rv, $server_was_stopped, $fw_rule_created, $fw_rule_removed)
2397         = &client_server_interaction($test_hr, \@packets, $USE_PREDEF_PKTS);
2398
2399     $rv = 0 unless $server_was_stopped;
2400
2401     if ($fw_rule_created) {
2402         &write_test_file("[-] new fw rule created.\n", $current_test_file);
2403         $rv = 0;
2404     } else {
2405         &write_test_file("[+] new fw rule not created.\n", $current_test_file);
2406     }
2407
2408     unless (&file_find_regex([qr/Args\scontain\sinvalid\sdata/],
2409             $MATCH_ALL, $server_test_file)) {
2410         $rv = 0;
2411     }
2412
2413     return $rv;
2414 }
2415
2416 sub overly_long_proto() {
2417     my $test_hr = shift;
2418
2419     my $rv = 1;
2420     my $server_was_stopped = 0;
2421     my $fw_rule_created = 0;
2422     my $fw_rule_removed = 0;
2423
2424     ### this packet was generated with a modified fwknop client via the
2425     ### following command line:
2426     #
2427     # LD_LIBRARY_PATH=../lib/.libs  ../client/.libs/fwknop -A \
2428     # "tcp`perl -e '{print "A"x"28"}'`/1" -a 127.0.0.2 -D 127.0.0.1 \
2429     # --get-key local_spa.key --verbose --verbose
2430     #
2431     # This problem was found by Fernando Arnaboldi of IOActive and exploits
2432     # a buffer overflow in the fwknopd servers prior to 2.0.3 from
2433     # authenticated clients.
2434     #
2435     my $spa_pkt =
2436         '/im5MiJQmOdzqrdWXv+AjEtAm/HsLrdaTFcSw3ZskqpGOdDIrSCz3VXbFfv7qDkc5Y4' .
2437         'q/k1mRXl9SGzpug87U5dZSyCdAr30z7/2kUFEPTGOQBi/x+L1t1pvdkm4xg13t09ldm' .
2438         '5OD8KiV6qzqLOvN4ULJjvvJJWBZ9qvo/f2Q9Wf67g2KHiwS6EeCINAuMoUw/mNRQMa4' .
2439         'oGnOXu3/DeWHJAwtSeh7EAr4';
2440
2441     my @packets = (
2442         {
2443             'proto'  => 'udp',
2444             'port'   => $default_spa_port,
2445             'dst_ip' => $loopback_ip,
2446             'data'   => $spa_pkt,
2447         },
2448     );
2449
2450     ($rv, $server_was_stopped, $fw_rule_created, $fw_rule_removed)
2451         = &client_server_interaction($test_hr, \@packets, $USE_PREDEF_PKTS);
2452
2453     $rv = 0 unless $server_was_stopped;
2454
2455     if ($fw_rule_created) {
2456         &write_test_file("[-] new fw rule created.\n", $current_test_file);
2457         $rv = 0;
2458     } else {
2459         &write_test_file("[+] new fw rule not created.\n", $current_test_file);
2460     }
2461
2462     unless (&file_find_regex([qr/Args\scontain\sinvalid\sdata/],
2463             $MATCH_ALL, $server_test_file)) {
2464         $rv = 0;
2465     }
2466
2467     return $rv;
2468 }
2469
2470 sub overly_long_port() {
2471     my $test_hr = shift;
2472
2473     my $rv = 1;
2474     my $server_was_stopped = 0;
2475     my $fw_rule_created = 0;
2476     my $fw_rule_removed = 0;
2477
2478     ### this packet was generated with a modified fwknop client via the
2479     ### following command line:
2480     #
2481     # LD_LIBRARY_PATH=../lib/.libs  ../client/.libs/fwknop -A \
2482     # "tcp/`perl -e '{print "1"x"40"}'`" -a 127.0.0.2 -D 127.0.0.1 \
2483     # --get-key local_spa.key --verbose --verbose
2484     #
2485     # This problem was found by Fernando Arnaboldi of IOActive and exploits
2486     # a buffer overflow in the fwknopd servers prior to 2.0.3 from
2487     # authenticated clients.
2488     #
2489     my $spa_pkt =
2490         '+JzxeTGlc6lwwzbJSrYChKx8bonWBIPajwGfEtGOaoglcMLbTY/GGXo/nxqiN1LykFS' .
2491         'lDFXgrkyx2emJ7NGzYqQPUYZxLdZRocR9aRIptvXLLIPBcIpJASi/TUiJlw7CDFMcj0' .
2492         'ptSBJJUZi0tozpKHETp3AgqfzyOy5FNs38aZsV5/sDl3Pt+kF7fTZJ+YLbmYY4yCUz2' .
2493         'ZUYoCaJ7X78ULyJTi5eT7nug';
2494
2495     my @packets = (
2496         {
2497             'proto'  => 'udp',
2498             'port'   => $default_spa_port,
2499             'dst_ip' => $loopback_ip,
2500             'data'   => $spa_pkt,
2501         },
2502     );
2503
2504     ($rv, $server_was_stopped, $fw_rule_created, $fw_rule_removed)
2505         = &client_server_interaction($test_hr, \@packets, $USE_PREDEF_PKTS);
2506
2507     $rv = 0 unless $server_was_stopped;
2508
2509     if ($fw_rule_created) {
2510         &write_test_file("[-] new fw rule created.\n", $current_test_file);
2511         $rv = 0;
2512     } else {
2513         &write_test_file("[+] new fw rule not created.\n", $current_test_file);
2514     }
2515
2516     unless (&file_find_regex([qr/Args\scontain\sinvalid\sdata/],
2517             $MATCH_ALL, $server_test_file)) {
2518         $rv = 0;
2519     }
2520
2521     return $rv;
2522 }
2523
2524 sub altered_base64_spa_data() {
2525     my $test_hr = shift;
2526
2527     my $rv = 1;
2528     my $server_was_stopped = 0;
2529     my $fw_rule_created = 0;
2530     my $fw_rule_removed = 0;
2531
2532     unless (&client_send_spa_packet($test_hr)) {
2533         &write_test_file("[-] fwknop client execution error.\n",
2534             $current_test_file);
2535         $rv = 0;
2536     }
2537
2538     my $spa_pkt = &get_spa_packet_from_file($current_test_file);
2539
2540     unless ($spa_pkt) {
2541         &write_test_file("[-] could not get SPA packet " .
2542             "from file: $current_test_file\n", $current_test_file);
2543         return 0;
2544     }
2545
2546     $spa_pkt =~ s|^(.{3}).|AAAA|;
2547
2548     my @packets = (
2549         {
2550             'proto'  => 'udp',
2551             'port'   => $default_spa_port,
2552             'dst_ip' => $loopback_ip,
2553             'data'   => $spa_pkt,
2554         },
2555     );
2556
2557     ($rv, $server_was_stopped, $fw_rule_created, $fw_rule_removed)
2558         = &client_server_interaction($test_hr, \@packets, $USE_PREDEF_PKTS);
2559
2560     $rv = 0 unless $server_was_stopped;
2561
2562     if ($fw_rule_created) {
2563         &write_test_file("[-] new fw rule created.\n", $current_test_file);
2564         $rv = 0;
2565     } else {
2566         &write_test_file("[+] new fw rule not created.\n", $current_test_file);
2567     }
2568
2569     unless (&file_find_regex([qr/Error\screating\sfko\scontext/],
2570             $MATCH_ALL, $server_test_file)) {
2571         $rv = 0;
2572     }
2573
2574     return $rv;
2575 }
2576
2577 sub appended_spa_data() {
2578     my $test_hr = shift;
2579
2580     my $rv = 1;
2581     my $server_was_stopped = 0;
2582     my $fw_rule_created = 0;
2583     my $fw_rule_removed = 0;
2584
2585     unless (&client_send_spa_packet($test_hr)) {
2586         &write_test_file("[-] fwknop client execution error.\n",
2587             $current_test_file);
2588         $rv = 0;
2589     }
2590
2591     my $spa_pkt = &get_spa_packet_from_file($current_test_file);
2592
2593     unless ($spa_pkt) {
2594         &write_test_file("[-] could not get SPA packet " .
2595             "from file: $current_test_file\n", $current_test_file);
2596         return 0;
2597     }
2598
2599     $spa_pkt .= 'AAAA';
2600
2601     my @packets = (
2602         {
2603             'proto'  => 'udp',
2604             'port'   => $default_spa_port,
2605             'dst_ip' => $loopback_ip,
2606             'data'   => $spa_pkt,
2607         },
2608     );
2609
2610     ($rv, $server_was_stopped, $fw_rule_created, $fw_rule_removed)
2611         = &client_server_interaction($test_hr, \@packets, $USE_PREDEF_PKTS);
2612
2613     $rv = 0 unless $server_was_stopped;
2614
2615     if ($fw_rule_created) {
2616         &write_test_file("[-] new fw rule created.\n", $current_test_file);
2617         $rv = 0;
2618     } else {
2619         &write_test_file("[+] new fw rule not created.\n", $current_test_file);
2620     }
2621
2622     unless (&file_find_regex([qr/Error\screating\sfko\scontext/],
2623             $MATCH_ALL, $server_test_file)) {
2624         $rv = 0;
2625     }
2626
2627     return $rv;
2628 }
2629
2630 sub prepended_spa_data() {
2631     my $test_hr = shift;
2632
2633     my $rv = 1;
2634     my $server_was_stopped = 0;
2635     my $fw_rule_created = 0;
2636     my $fw_rule_removed = 0;
2637
2638     unless (&client_send_spa_packet($test_hr)) {
2639         &write_test_file("[-] fwknop client execution error.\n",
2640             $current_test_file);
2641         $rv = 0;
2642     }
2643
2644     my $spa_pkt = &get_spa_packet_from_file($current_test_file);
2645
2646     unless ($spa_pkt) {
2647         &write_test_file("[-] could not get SPA packet " .
2648             "from file: $current_test_file\n", $current_test_file);
2649         return 0;
2650     }
2651
2652     $spa_pkt = 'AAAA' . $spa_pkt;
2653
2654     my @packets = (
2655         {
2656             'proto'  => 'udp',
2657             'port'   => $default_spa_port,
2658             'dst_ip' => $loopback_ip,
2659             'data'   => $spa_pkt,
2660         },
2661     );
2662
2663     ($rv, $server_was_stopped, $fw_rule_created, $fw_rule_removed)
2664         = &client_server_interaction($test_hr, \@packets, $USE_PREDEF_PKTS);
2665
2666     $rv = 0 unless $server_was_stopped;
2667
2668     if ($fw_rule_created) {
2669         &write_test_file("[-] new fw rule created.\n", $current_test_file);
2670         $rv = 0;
2671     } else {
2672         &write_test_file("[+] new fw rule not created.\n", $current_test_file);
2673     }
2674
2675     unless (&file_find_regex([qr/Error\screating\sfko\scontext/],
2676             $MATCH_ALL, $server_test_file)) {
2677         $rv = 0;
2678     }
2679
2680     return $rv;
2681 }
2682
2683 sub server_start() {
2684     my $test_hr = shift;
2685
2686     my ($rv, $server_was_stopped, $fw_rule_created, $fw_rule_removed)
2687         = &client_server_interaction($test_hr, [], $USE_PREDEF_PKTS);
2688
2689     unless (&file_find_regex([qr/Starting\sfwknopd\smain\sevent\sloop/],
2690             $MATCH_ALL, $server_test_file)) {
2691         $rv = 0;
2692     }
2693
2694     $rv = 0 unless $server_was_stopped;
2695
2696     return $rv;
2697 }
2698
2699 sub server_stop() {
2700     my $test_hr = shift;
2701
2702     my ($rv, $server_was_stopped, $fw_rule_created, $fw_rule_removed)
2703         = &client_server_interaction($test_hr, [], $USE_PREDEF_PKTS);
2704
2705     $rv = 0 unless $server_was_stopped;
2706
2707     return $rv;
2708 }
2709
2710 sub server_packet_limit() {
2711     my $test_hr = shift;
2712
2713     my @packets = (
2714         {
2715             'proto'  => 'udp',
2716             'port'   => $default_spa_port,
2717             'dst_ip' => $loopback_ip,
2718             'data'   => 'A'x700,
2719         },
2720     );
2721
2722     my ($rv, $server_was_stopped, $fw_rule_created, $fw_rule_removed)
2723         = &client_server_interaction($test_hr, \@packets, $USE_PREDEF_PKTS);
2724
2725     if (&is_fwknopd_running()) {
2726         &stop_fwknopd();
2727         $rv = 0;
2728     }
2729
2730     unless (&file_find_regex([qr/count\slimit\sof\s1\sreached/],
2731             $MATCH_ALL, $server_test_file)) {
2732         $rv = 0;
2733     }
2734
2735     unless (&file_find_regex([qr/Shutting\sDown\sfwknopd/i],
2736             $MATCH_ALL, $server_test_file)) {
2737         $rv = 0;
2738     }
2739
2740     return $rv;
2741 }
2742
2743 sub server_ignore_small_packets() {
2744     my $test_hr = shift;
2745
2746     my @packets = (
2747         {
2748             'proto'  => 'udp',
2749             'port'   => $default_spa_port,
2750             'dst_ip' => $loopback_ip,
2751             'data'   => 'A'x120,  ### < MIN_SPA_DATA_SIZE
2752         },
2753     );
2754
2755     my ($rv, $server_was_stopped, $fw_rule_created, $fw_rule_removed)
2756         = &client_server_interaction($test_hr, \@packets, $USE_PREDEF_PKTS);
2757
2758     sleep 2;
2759
2760     if (&is_fwknopd_running()) {
2761         &stop_fwknopd();
2762         $rv = 0;
2763     }
2764
2765     return $rv;
2766 }
2767
2768 sub client_server_interaction() {
2769     my ($test_hr, $pkts_hr, $spa_client_flag) = @_;
2770
2771     my $rv = 1;
2772     my $server_was_stopped = 1;
2773     my $fw_rule_created = 1;
2774     my $fw_rule_removed = 0;
2775
2776     ### start fwknopd to monitor for the SPA packet over the loopback interface
2777     my $fwknopd_parent_pid = &start_fwknopd($test_hr);
2778
2779     ### give fwknopd a chance to parse its config and start sniffing
2780     ### on the loopback interface
2781     if ($use_valgrind) {
2782         sleep 3;
2783     } else {
2784         sleep 2;
2785     }
2786
2787     ### send the SPA packet(s) to the server either manually using IO::Socket or
2788     ### with the fwknopd client
2789     if ($spa_client_flag == $USE_CLIENT) {
2790         unless (&client_send_spa_packet($test_hr)) {
2791             &write_test_file("[-] fwknop client execution error.\n",
2792                 $current_test_file);
2793             $rv = 0;
2794         }
2795     } else {
2796         &send_packets($pkts_hr);
2797     }
2798
2799     ### check to see if the SPA packet resulted in a new fw access rule
2800     my $ctr = 0;
2801     while (not &is_fw_rule_active($test_hr)) {
2802         &write_test_file("[-] new fw rule does not exist.\n",
2803             $current_test_file);
2804         $ctr++;
2805         last if $ctr == 3;
2806         sleep 1;
2807     }
2808     if ($ctr == 3) {
2809         $fw_rule_created = 0;
2810         $fw_rule_removed = 0;
2811     }
2812
2813     &time_for_valgrind() if $use_valgrind;
2814
2815     if ($fw_rule_created) {
2816         sleep 3;  ### allow time for rule time out.
2817         if (&is_fw_rule_active($test_hr)) {
2818             &write_test_file("[-] new fw rule not timed out.\n",
2819                 $current_test_file);
2820             $rv = 0;
2821         } else {
2822             &write_test_file("[+] new fw rule timed out.\n",
2823                 $current_test_file);
2824             $fw_rule_removed = 1;
2825         }
2826     }
2827
2828     if (&is_fwknopd_running()) {
2829         &stop_fwknopd();
2830         unless (&file_find_regex([qr/Got\sSIGTERM/],
2831                 $MATCH_ALL, $server_test_file)) {
2832             $server_was_stopped = 0;
2833         }
2834     } else {
2835         &write_test_file("[-] server is not running.\n",
2836             $current_test_file);
2837         $server_was_stopped = 0;
2838     }
2839
2840     return ($rv, $server_was_stopped, $fw_rule_created, $fw_rule_removed);
2841 }
2842
2843 sub get_spa_packet_from_file() {
2844     my $file = shift;
2845
2846     my $spa_pkt = '';
2847
2848     my $found_trigger_line = 0;
2849     open F, "< $file" or die "[*] Could not open file $file: $!";
2850     while (<F>) {
2851         if (/final\spacked/i) {
2852             $found_trigger_line = 1;
2853             next;
2854         }
2855         next unless $found_trigger_line;
2856
2857         ### the next line with non whitespace is the SPA packet
2858         if (/(\S+)/) {
2859             $spa_pkt = $1;
2860             last;
2861         }
2862     }
2863     close F;
2864
2865     return $spa_pkt;
2866 }
2867
2868 sub send_packets() {
2869     my $pkts_ar = shift;
2870
2871     open F, ">> $current_test_file" or die $!;
2872     print F "[+] send_packets(): Sending the following packets...\n";
2873     print F Dumper $pkts_ar;
2874     close F;
2875
2876     for my $pkt_hr (@$pkts_ar) {
2877         if ($pkt_hr->{'proto'} eq 'tcp' or $pkt_hr->{'proto'} eq 'udp') {
2878             my $socket = IO::Socket::INET->new(
2879                 PeerAddr => $pkt_hr->{'dst_ip'},
2880                 PeerPort => $pkt_hr->{'port'},
2881                 Proto    => $pkt_hr->{'proto'},
2882                 Timeout  => 1
2883             ) or die "[*] Could not acquire $pkt_hr->{'proto'}/$pkt_hr->{'port'} " .
2884                 "socket to $pkt_hr->{'dst_ip'}: $!";
2885
2886             $socket->send($pkt_hr->{'data'});
2887             undef $socket;
2888
2889         } elsif ($pkt_hr->{'proto'} eq 'http') {
2890             ### FIXME
2891         } elsif ($pkt_hr->{'proto'} eq 'icmp') {
2892             ### FIXME
2893         }
2894
2895         sleep $pkt_hr->{'delay'} if defined $pkt_hr->{'delay'};
2896     }
2897     return;
2898 }
2899
2900 sub generic_exec() {
2901     my $test_hr = shift;
2902
2903     my $rv = 1;
2904
2905     my $exec_rv = &run_cmd($test_hr->{'cmdline'},
2906                 $cmd_out_tmp, $current_test_file);
2907
2908     if ($test_hr->{'exec_err'} eq $YES) {
2909         $rv = 0 if $exec_rv;
2910     } else {
2911         $rv = 0 unless $exec_rv;
2912     }
2913
2914     if ($test_hr->{'positive_output_matches'}) {
2915         $rv = 0 unless &file_find_regex(
2916             $test_hr->{'positive_output_matches'},
2917             $MATCH_ALL, $current_test_file);
2918     }
2919
2920     if ($test_hr->{'negative_output_matches'}) {
2921         $rv = 0 if &file_find_regex(
2922             $test_hr->{'negative_output_matches'},
2923             $MATCH_ANY, $current_test_file);
2924     }
2925
2926     return $rv;
2927 }
2928
2929 ### check for PIE
2930 sub pie_binary() {
2931     my $test_hr = shift;
2932     return 0 unless $test_hr->{'binary'};
2933     &run_cmd("./hardening-check $test_hr->{'binary'}",
2934             $cmd_out_tmp, $current_test_file);
2935     return 0 if &file_find_regex([qr/Position\sIndependent.*:\sno/i],
2936         $MATCH_ALL, $current_test_file);
2937     return 1;
2938 }
2939
2940 ### check for stack protection
2941 sub stack_protected_binary() {
2942     my $test_hr = shift;
2943     return 0 unless $test_hr->{'binary'};
2944     &run_cmd("./hardening-check $test_hr->{'binary'}",
2945             $cmd_out_tmp, $current_test_file);
2946     return 0 if &file_find_regex([qr/Stack\sprotected.*:\sno/i],
2947         $MATCH_ALL, $current_test_file);
2948     return 1;
2949 }
2950
2951 ### check for fortified source functions
2952 sub fortify_source_functions() {
2953     my $test_hr = shift;
2954     return 0 unless $test_hr->{'binary'};
2955     &run_cmd("./hardening-check $test_hr->{'binary'}",
2956             $cmd_out_tmp, $current_test_file);
2957     return 0 if &file_find_regex([qr/Fortify\sSource\sfunctions:\sno/i],
2958         $MATCH_ALL, $current_test_file);
2959     return 1;
2960 }
2961
2962 ### check for read-only relocations
2963 sub read_only_relocations() {
2964     my $test_hr = shift;
2965     return 0 unless $test_hr->{'binary'};
2966     &run_cmd("./hardening-check $test_hr->{'binary'}",
2967             $cmd_out_tmp, $current_test_file);
2968     return 0 if &file_find_regex([qr/Read.only\srelocations:\sno/i],
2969         $MATCH_ALL, $current_test_file);
2970     return 1;
2971 }
2972
2973 ### check for immediate binding
2974 sub immediate_binding() {
2975     my $test_hr = shift;
2976     return 0 unless $test_hr->{'binary'};
2977     &run_cmd("./hardening-check $test_hr->{'binary'}",
2978             $cmd_out_tmp, $current_test_file);
2979     return 0 if &file_find_regex([qr/Immediate\sbinding:\sno/i],
2980         $MATCH_ALL, $current_test_file);
2981     return 1;
2982 }
2983
2984 sub specs() {
2985
2986      &run_cmd("LD_LIBRARY_PATH=$lib_dir $valgrind_str $fwknopdCmd " .
2987             "$default_server_conf_args --fw-list-all",
2988             $cmd_out_tmp, $current_test_file);
2989
2990     my $have_gpgme = 0;
2991
2992     for my $cmd (
2993         'uname -a',
2994         'uptime',
2995         'ifconfig -a',
2996         'ls -l /etc', 'if [ -e /etc/issue ]; then cat /etc/issue; fi',
2997         'if [ `which iptables` ]; then iptables -V; fi',
2998         'if [ -e /proc/cpuinfo ]; then cat /proc/cpuinfo; fi',
2999         'if [ -e /proc/config.gz ]; then zcat /proc/config.gz; fi',
3000         'if [ `which gpg` ]; then gpg --version; fi',
3001         'if [ `which tcpdump` ]; then ldd `which tcpdump`; fi',
3002         "ldd $fwknopCmd",
3003         "ldd $fwknopdCmd",
3004         "ldd $libfko_bin",
3005         'ls -l /usr/lib/*pcap*',
3006         'ls -l /usr/local/lib/*pcap*',
3007         'ls -l /usr/lib/*fko*',
3008         'ls -l /usr/local/lib/*fko*',
3009     ) {
3010         &run_cmd($cmd, $cmd_out_tmp, $current_test_file);
3011
3012         if ($cmd =~ /^ldd/) {
3013             $have_gpgme++ if &file_find_regex([qr/gpgme/],
3014                 $MATCH_ALL, $cmd_out_tmp);
3015         }
3016     }
3017
3018     ### all three of fwknop/fwknopd/libfko must link against gpgme in order
3019     ### to enable gpg tests
3020     unless ($have_gpgme == 3) {
3021         push @tests_to_exclude, qr/GPG/;
3022     }
3023
3024     return 1;
3025 }
3026
3027 sub time_for_valgrind() {
3028     my $ctr = 0;
3029     while (&run_cmd("ps axuww | grep LD_LIBRARY_PATH | " .
3030             "grep valgrind |grep -v perl | grep -v grep",
3031             $cmd_out_tmp, $current_test_file)) {
3032         $ctr++;
3033         last if $ctr == 5;
3034         sleep 1;
3035     }
3036     return;
3037 }
3038
3039 sub anonymize_results() {
3040     my $rv = 0;
3041     die "[*] $output_dir does not exist" unless -d $output_dir;
3042     die "[*] $logfile does not exist, has $0 been executed?"
3043         unless -e $logfile;
3044     if (-e $tarfile) {
3045         unlink $tarfile or die "[*] Could not unlink $tarfile: $!";
3046     }
3047
3048     ### remove non-loopback IP addresses
3049     my $search_re = qr/\b127\.0\.0\.1\b/;
3050     system "perl -p -i -e 's|$search_re|00MY1271STR00|g' $output_dir/*.test";
3051     $search_re = qr/\b127\.0\.0\.2\b/;
3052     system "perl -p -i -e 's|$search_re|00MY1272STR00|g' $output_dir/*.test";
3053     $search_re = qr/\b0\.0\.0\.0\b/;
3054     system "perl -p -i -e 's|$search_re|00MY0000STR00|g' $output_dir/*.test";
3055     $search_re = qr/\b(?:[0-2]?\d{1,2}\.){3}[0-2]?\d{1,2}\b/;
3056     system "perl -p -i -e 's|$search_re|N.N.N.N|g' $output_dir/*.test";
3057     system "perl -p -i -e 's|00MY1271STR00|127.0.0.1|g' $output_dir/*.test";
3058     system "perl -p -i -e 's|00MY1272STR00|127.0.0.2|g' $output_dir/*.test";
3059     system "perl -p -i -e 's|00MY0000STR00|0.0.0.0|g' $output_dir/*.test";
3060
3061     ### remove hostname from any uname output
3062     $search_re = qr/\suname\s+\-a\s*\n\s*(\S+)\s+\S+/;
3063     system "perl -p -i -e 'undef \$/; s|$search_re" .
3064         "| uname -a\n\$1 (removed)|s' $output_dir/*.test";
3065
3066     $search_re = qr/uname=\x27(\S+)\s+\S+/;
3067     system "perl -p -i -e 's|$search_re|uname= \$1 (removed)|' $output_dir/*.test";
3068
3069     ### create tarball
3070     system "tar cvfz $tarfile $logfile $output_dir";
3071     print "[+] Anonymized test results file: $tarfile\n";
3072     if (-e $tarfile) {
3073         $rv = 1;
3074     }
3075     return $rv;
3076 }
3077
3078
3079 sub write_pid() {
3080     my $test_hr = shift;
3081
3082     open F, "> $default_pid_file" or die $!;
3083     print F "1\n";
3084     close F;
3085
3086     &server_start($test_hr);
3087
3088     open F, "< $default_pid_file" or die $!;
3089     my $pid = <F>;
3090     chomp $pid;
3091     close F;
3092
3093     if ($pid != 1) {
3094         return 1;
3095     }
3096
3097     return 0;
3098 }
3099
3100 sub start_fwknopd() {
3101     my $test_hr = shift;
3102
3103     &write_test_file("[+] TEST: $test_hr->{'msg'}\n", $server_test_file);
3104
3105     my $pid = fork();
3106     die "[*] Could not fork: $!" unless defined $pid;
3107
3108     if ($pid == 0) {
3109
3110         ### we are the child, so start fwknopd
3111         exit &run_cmd($test_hr->{'fwknopd_cmdline'},
3112             $server_cmd_tmp, $server_test_file);
3113     }
3114     return $pid;
3115 }
3116
3117 sub write_key() {
3118     my ($key, $file) = @_;
3119
3120     open K, "> $file" or die "[*] Could not open $file: $!";
3121     print K "$loopback_ip: $key\n";
3122     print K "localhost: $key\n";
3123     print K "some.host.through.proxy.com: $key\n";
3124     close K;
3125     return;
3126 }
3127
3128 sub dump_pids() {
3129     open C, ">> $current_test_file"
3130         or die "[*] Could not open $current_test_file: $!";
3131     print C "\n" . localtime() . " [+] PID dump:\n";
3132     close C;
3133     &run_cmd("ps auxww | grep knop |grep -v grep",
3134         $cmd_out_tmp, $current_test_file);
3135     return;
3136 }
3137
3138 sub run_cmd() {
3139     my ($cmd, $cmd_out, $file) = @_;
3140
3141     if (-e $file) {
3142         open F, ">> $file"
3143             or die "[*] Could not open $file: $!";
3144         print F localtime() . " CMD: $cmd\n";
3145         close F;
3146     } else {
3147         open F, "> $file"
3148             or die "[*] Could not open $file: $!";
3149         print F localtime() . " CMD: $cmd\n";
3150         close F;
3151     }
3152
3153     my $rv = ((system "$cmd > $cmd_out 2>&1") >> 8);
3154
3155     open C, "< $cmd_out" or die "[*] Could not open $cmd_out: $!";
3156     my @cmd_lines = <C>;
3157     close C;
3158
3159     open F, ">> $file" or die "[*] Could not open $file: $!";
3160     print F $_ for @cmd_lines;
3161     close F;
3162
3163     if ($rv == 0) {
3164         return 1;
3165     }
3166     return 0;
3167 }
3168
3169 sub dots_print() {
3170     my $msg = shift;
3171     &logr($msg);
3172     my $dots = '';
3173     for (my $i=length($msg); $i < $PRINT_LEN; $i++) {
3174         $dots .= '.';
3175     }
3176     &logr($dots);
3177     return;
3178 }
3179
3180 sub init() {
3181
3182     $|++; ### turn off buffering
3183
3184     $< == 0 && $> == 0 or
3185         die "[*] $0: You must be root (or equivalent ",
3186             "UID 0 account) to effectively test fwknop";
3187
3188     ### validate test hashes
3189     my $hash_num = 0;
3190     for my $test_hr (@tests) {
3191         for my $key (keys %test_keys) {
3192             if ($test_keys{$key} == $REQUIRED) {
3193                 die "[*] Missing '$key' element in hash: $hash_num"
3194                     unless defined $test_hr->{$key};
3195             } else {
3196                 $test_hr->{$key} = '' unless defined $test_hr->{$key};
3197             }
3198         }
3199         $hash_num++;
3200     }
3201
3202     if ($use_valgrind) {
3203         die "[*] $valgrindCmd exec problem, use --valgrind-path"
3204             unless -e $valgrindCmd and -x $valgrindCmd;
3205     }
3206
3207     die "[*] $conf_dir directory does not exist." unless -d $conf_dir;
3208     die "[*] $lib_dir directory does not exist." unless -d $lib_dir;
3209
3210     for my $name (keys %cf) {
3211         die "[*] $cf{$name} does not exist" unless -e $cf{$name};
3212     }
3213
3214     if (-d $output_dir) {
3215         if (-d "${output_dir}.last") {
3216             rmtree "${output_dir}.last"
3217                 or die "[*] rmtree ${output_dir}.last $!";
3218         }
3219         mkdir "${output_dir}.last"
3220             or die "[*] ${output_dir}.last: $!";
3221         for my $file (glob("$output_dir/*.test")) {
3222             if ($file =~ m|.*/(.*)|) {
3223                 copy $file, "${output_dir}.last/$1" or die $!;
3224             }
3225         }
3226         if (-e "$output_dir/init") {
3227             copy "$output_dir/init", "${output_dir}.last/init";
3228         }
3229         if (-e $logfile) {
3230             copy $logfile, "${output_dir}.last/$logfile" or die $!;
3231         }
3232         $saved_last_results = 1;
3233     } else {
3234         mkdir $output_dir or die "[*] Could not mkdir $output_dir: $!";
3235     }
3236     unless (-d $run_dir) {
3237         mkdir $run_dir or die "[*] Could not mkdir $run_dir: $!";
3238     }
3239
3240     for my $file (glob("$output_dir/*.test")) {
3241         unlink $file or die "[*] Could not unlink($file)";
3242     }
3243     if (-e "$output_dir/init") {
3244         unlink "$output_dir/init" or die $!;
3245     }
3246
3247     if (-e $logfile) {
3248         unlink $logfile or die $!;
3249     }
3250
3251     if ($test_include) {
3252         for my $re (split /\s*,\s*/, $test_include) {
3253             push @tests_to_include, qr/$re/;
3254         }
3255     }
3256     if ($test_exclude) {
3257         for my $re (split /\s*,\s*/, $test_exclude) {
3258             push @tests_to_exclude, qr/$re/;
3259         }
3260     }
3261
3262     ### make sure no fwknopd instance is currently running
3263     die "[*] Please stop the running fwknopd instance."
3264         if &is_fwknopd_running();
3265
3266     unless ($enable_recompilation_warnings_check) {
3267         push @tests_to_exclude, qr/recompilation/;
3268     }
3269
3270     unless ($enable_make_distcheck) {
3271         push @tests_to_exclude, qr/distcheck/;
3272     }
3273
3274     unless ($enable_client_ip_resolve_test) {
3275         push @tests_to_exclude, qr/IP resolve/;
3276     }
3277
3278     $sudo_path = &find_command('sudo');
3279
3280     unless ((&find_command('cc') or &find_command('gcc')) and &find_command('make')) {
3281         ### disable compilation checks
3282         push @tests_to_exclude, qr/recompilation/;
3283     }
3284
3285     open UNAME, "uname |" or die "[*] Could not execute uname: $!";
3286     while (<UNAME>) {
3287         if (/linux/i) {
3288             $platform = $LINUX;
3289             last;
3290         } elsif (/freebsd/i) {
3291             $platform = $FREEBSD;
3292             last;
3293         }
3294     }
3295     close UNAME;
3296
3297     unless ($platform eq $LINUX) {
3298         push @tests_to_exclude, qr/NAT/;
3299     }
3300     unless ($platform eq $FREEBSD or $platform eq $MACOSX) {
3301         push @tests_to_exclude, qr|active/expire sets|;
3302     }
3303
3304     if (-e $default_digest_file) {
3305         unlink $default_digest_file;
3306     }
3307
3308     return;
3309 }
3310
3311 sub identify_loopback_intf() {
3312     return if $loopback_intf;
3313
3314     ### Linux:
3315
3316     ### lo    Link encap:Local Loopback
3317     ###       inet addr:127.0.0.1  Mask:255.0.0.0
3318     ###       inet6 addr: ::1/128 Scope:Host
3319     ###       UP LOOPBACK RUNNING  MTU:16436  Metric:1
3320     ###       RX packets:534709 errors:0 dropped:0 overruns:0 frame:0
3321     ###       TX packets:534709 errors:0 dropped:0 overruns:0 carrier:0
3322     ###       collisions:0 txqueuelen:0
3323     ###       RX bytes:101110617 (101.1 MB)  TX bytes:101110617 (101.1 MB)
3324
3325     ### Freebsd:
3326
3327     ### lo0: flags=8049<UP,LOOPBACK,RUNNING,MULTICAST> metric 0 mtu 16384
3328     ###         options=3<RXCSUM,TXCSUM>
3329     ###         inet6 fe80::1%lo0 prefixlen 64 scopeid 0x2
3330     ###         inet6 ::1 prefixlen 128
3331     ###         inet 127.0.0.1 netmask 0xff000000
3332     ###         nd6 options=3<PERFORMNUD,ACCEPT_RTADV>
3333
3334     my $intf = '';
3335     my $found_loopback_intf = 0;
3336
3337     my $cmd = 'ifconfig -a';
3338     open C, "$cmd |" or die "[*] (use --loopback <name>) $cmd: $!";
3339     while (<C>) {
3340         if (/^(\S+?):?\s+.*loopback/i) {
3341             $intf = $1;
3342             next;
3343         }
3344         if (/^\S/ and $intf and not $found_loopback_intf) {
3345             ### should not happen
3346             last;
3347         }
3348         if ($intf and /\b127\.0\.0\.1\b/) {
3349             $found_loopback_intf = 1;
3350             last;
3351         }
3352     }
3353     close C;
3354
3355     die "[*] could not determine loopback interface, use --loopback <name>"
3356         unless $found_loopback_intf;
3357
3358     $loopback_intf = $intf;
3359
3360     return;
3361 }
3362
3363 sub parse_valgrind_flagged_functions() {
3364     for my $file (glob("$output_dir/*.test")) {
3365         my $type = 'server';
3366         $type = 'client' if $file =~ /\d\.test/;
3367         open F, "< $file" or die $!;
3368         while (<F>) {
3369             ### ==30969==    by 0x4E3983A: fko_set_username (fko_user.c:65)
3370             if (/^==.*\sby\s\S+\:\s(\S+)\s(.*)/) {
3371                 $valgrind_flagged_fcns{$type}{"$1 $2"}++;
3372                 $valgrind_flagged_fcns_unique{$type}{$1}++;
3373             }
3374         }
3375         close F;
3376     }
3377
3378     open F, ">> $current_test_file" or die $!;
3379     for my $type ('client', 'server') {
3380         print F "\n[+] fwknop $type functions (unique view):\n";
3381         next unless defined $valgrind_flagged_fcns_unique{$type};
3382         for my $fcn (sort {$valgrind_flagged_fcns_unique{$type}{$b}
3383                 <=> $valgrind_flagged_fcns_unique{$type}{$a}}
3384                 keys %{$valgrind_flagged_fcns_unique{$type}}) {
3385             printf F "    %5d : %s\n", $valgrind_flagged_fcns_unique{$type}{$fcn}, $fcn;
3386         }
3387         print F "\n[+] fwknop $type functions (with call line numbers):\n";
3388         for my $fcn (sort {$valgrind_flagged_fcns{$type}{$b}
3389                 <=> $valgrind_flagged_fcns{$type}{$a}} keys %{$valgrind_flagged_fcns{$type}}) {
3390             printf F "    %5d : %s\n", $valgrind_flagged_fcns{$type}{$fcn}, $fcn;
3391         }
3392         next unless defined $valgrind_flagged_fcns{$type};
3393
3394     }
3395     close F;
3396     return 1;
3397 }
3398
3399 sub is_fw_rule_active() {
3400     my $test_hr = shift;
3401
3402     my $conf_args = $default_server_conf_args;
3403
3404     if ($test_hr->{'server_conf'}) {
3405         $conf_args = "-c $test_hr->{'server_conf'} -a $cf{'def_access'} " .
3406             "-d $default_digest_file -p $default_pid_file";
3407     }
3408
3409     if ($test_hr->{'no_ip_check'}) {
3410         return 1 if &run_cmd("LD_LIBRARY_PATH=$lib_dir $fwknopdCmd " .
3411                 qq{$conf_args --fw-list | grep -v "# DISABLED" |grep _exp_},
3412                 $cmd_out_tmp, $current_test_file);
3413     } else {
3414         return 1 if &run_cmd("LD_LIBRARY_PATH=$lib_dir $fwknopdCmd " .
3415                 qq{$conf_args --fw-list | grep -v "# DISABLED" |grep $fake_ip |grep _exp_},
3416                 $cmd_out_tmp, $current_test_file);
3417     }
3418
3419     return 0;
3420 }
3421
3422 sub is_fwknopd_running() {
3423
3424     sleep 2 if $use_valgrind;
3425
3426     &run_cmd("LD_LIBRARY_PATH=$lib_dir $fwknopdCmd $default_server_conf_args " .
3427         "--status", $cmd_out_tmp, $current_test_file);
3428
3429     return 1 if &file_find_regex([qr/Detected\sfwknopd\sis\srunning/i],
3430             $MATCH_ALL, $cmd_out_tmp);
3431
3432     return 0;
3433 }
3434
3435 sub stop_fwknopd() {
3436
3437     &run_cmd("LD_LIBRARY_PATH=$lib_dir $fwknopdCmd " .
3438         "$default_server_conf_args -K", $cmd_out_tmp, $current_test_file);
3439