8 use Getopt::Long 'GetOptions';
11 #==================== config =====================
12 my $logfile = 'test.log';
13 my $local_key_file = 'local_spa.key';
14 my $output_dir = 'output';
15 my $lib_dir = '../lib/.libs';
16 my $conf_dir = 'conf';
18 my $configure_path = '../configure';
19 my $cmd_out_tmp = 'cmd.out';
20 my $server_cmd_tmp = 'server_cmd.out';
21 my $gpg_client_home_dir = "$conf_dir/client-gpg";
23 my $nat_conf = "$conf_dir/nat_fwknopd.conf";
24 my $default_conf = "$conf_dir/default_fwknopd.conf";
25 my $default_access_conf = "$conf_dir/default_access.conf";
26 my $ecb_mode_access_conf = "$conf_dir/ecb_mode_access.conf";
27 my $ctr_mode_access_conf = "$conf_dir/ctr_mode_access.conf";
28 my $cfb_mode_access_conf = "$conf_dir/cfb_mode_access.conf";
29 my $ofb_mode_access_conf = "$conf_dir/ofb_mode_access.conf";
30 my $expired_access_conf = "$conf_dir/expired_stanza_access.conf";
31 my $future_expired_access_conf = "$conf_dir/future_expired_stanza_access.conf";
32 my $expired_epoch_access_conf = "$conf_dir/expired_epoch_stanza_access.conf";
33 my $invalid_expire_access_conf = "$conf_dir/invalid_expire_access.conf";
34 my $invalid_source_access_conf = "$conf_dir/invalid_source_access.conf";
35 my $force_nat_access_conf = "$conf_dir/force_nat_access.conf";
36 my $dual_key_usage_access_conf = "$conf_dir/dual_key_usage_access.conf";
37 my $gpg_access_conf = "$conf_dir/gpg_access.conf";
38 my $default_digest_file = "$run_dir/digest.cache";
39 my $default_pid_file = "$run_dir/fwknopd.pid";
40 my $open_ports_access_conf = "$conf_dir/open_ports_access.conf";
41 my $multi_gpg_access_conf = "$conf_dir/multi_gpg_access.conf";
42 my $multi_stanzas_access_conf = "$conf_dir/multi_stanzas_access.conf";
43 my $multi_stanzas_with_broken_keys_conf = "$conf_dir/multi_stanzas_with_broken_keys.conf";
44 my $mismatch_open_ports_access_conf = "$conf_dir/mismatch_open_ports_access.conf";
45 my $require_user_access_conf = "$conf_dir/require_user_access.conf";
46 my $mismatch_user_access_conf = "$conf_dir/mismatch_user_access.conf";
47 my $require_src_access_conf = "$conf_dir/require_src_access.conf";
48 my $no_source_match_access_conf = "$conf_dir/no_source_match_access.conf";
49 my $no_subnet_source_match_access_conf = "$conf_dir/no_subnet_source_match_access.conf";
50 my $no_multi_source_match_access_conf = "$conf_dir/no_multi_source_match_access.conf";
51 my $multi_source_match_access_conf = "$conf_dir/multi_source_match_access.conf";
52 my $ip_source_match_access_conf = "$conf_dir/ip_source_match_access.conf";
53 my $subnet_source_match_access_conf = "$conf_dir/subnet_source_match_access.conf";
55 my $fwknopCmd = '../client/.libs/fwknop';
56 my $fwknopdCmd = '../server/.libs/fwknopd';
57 my $libfko_bin = "$lib_dir/libfko.so"; ### this is usually a link
58 my $valgrindCmd = '/usr/bin/valgrind';
60 my $gpg_server_key = '361BBAD4';
61 my $gpg_client_key = '6A3FAD56';
63 my $loopback_ip = '127.0.0.1';
64 my $fake_ip = '127.0.0.2';
65 my $internal_nat_host = '192.168.1.2';
66 my $force_nat_host = '192.168.1.123';
67 my $default_spa_port = 62201;
68 my $non_std_spa_port = 12345;
70 my $spoof_user = 'testuser';
71 #================== end config ===================
76 my $test_include = '';
77 my @tests_to_include = ();
78 my $test_exclude = '';
79 my @tests_to_exclude = ();
80 my %valgrind_flagged_fcns = ();
81 my %valgrind_flagged_fcns_unique = ();
85 my $loopback_intf = '';
86 my $anonymize_results = 0;
87 my $current_test_file = "$output_dir/init";
88 my $tarfile = 'test_fwknop.tar.gz';
89 my $server_test_file = '';
91 my $valgrind_str = '';
92 my $saved_last_results = 0;
94 my $enable_recompilation_warnings_check = 0;
95 my $enable_profile_coverage_check = 0;
103 my $USE_PREDEF_PKTS = 1;
107 my $NEW_RULE_REQUIRED = 1;
108 my $REQUIRE_NO_NEW_RULE = 2;
109 my $NEW_RULE_REMOVED = 1;
110 my $REQUIRE_NO_NEW_REMOVED = 2;
112 my $ip_re = qr|(?:[0-2]?\d{1,2}\.){3}[0-2]?\d{1,2}|; ### IPv4
116 exit 1 unless GetOptions(
117 'Anonymize-results' => \$anonymize_results,
118 'fwknop-path=s' => \$fwknopCmd,
119 'fwknopd-path=s' => \$fwknopdCmd,
120 'libfko-path=s' => \$libfko_bin,
121 'loopback-intf=s' => \$loopback_intf,
122 'test-include=s' => \$test_include,
123 'include=s' => \$test_include, ### synonym
124 'test-exclude=s' => \$test_exclude,
125 'exclude=s' => \$test_exclude, ### synonym
126 'enable-recompile-check' => \$enable_recompilation_warnings_check,
127 'enable-profile-coverage-check' => \$enable_profile_coverage_check,
128 'List-mode' => \$list_mode,
129 'enable-valgrind' => \$use_valgrind,
130 'valgrind-path=s' => \$valgrindCmd,
131 'output-dir=s' => \$output_dir,
132 'diff' => \$diff_mode,
133 'diff-dir1=s' => \$diff_dir1,
134 'diff-dir2=s' => \$diff_dir2,
140 ### create an anonymized tar file of test suite results that can be
141 ### emailed around to assist in debugging fwknop communications
142 exit &anonymize_results() if $anonymize_results;
144 &identify_loopback_intf();
146 $valgrind_str = "$valgrindCmd --leak-check=full " .
147 "--show-reachable=yes --track-origins=yes" if $use_valgrind;
149 my $intf_str = "-i $loopback_intf --foreground --verbose --verbose";
151 my $default_client_args = "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
152 "$fwknopCmd -A tcp/22 -a $fake_ip -D $loopback_ip --get-key " .
153 "$local_key_file --verbose --verbose";
155 my $default_client_gpg_args = "$default_client_args " .
156 "--gpg-recipient-key $gpg_server_key " .
157 "--gpg-signer-key $gpg_client_key " .
158 "--gpg-home-dir $gpg_client_home_dir";
160 my $default_server_conf_args = "-c $default_conf -a $default_access_conf " .
161 "-d $default_digest_file -p $default_pid_file";
163 my $default_server_gpg_args = "LD_LIBRARY_PATH=$lib_dir " .
164 "$valgrind_str $fwknopdCmd -c $default_conf " .
165 "-a $gpg_access_conf $intf_str " .
166 "-d $default_digest_file -p $default_pid_file";
168 ### point the compiled binaries at the local libary path
169 ### instead of any installed libfko instance
170 $ENV{'LD_LIBRARY_PATH'} = $lib_dir;
172 ### main array that defines the tests we will run
175 'category' => 'recompilation',
176 'detail' => 'recompile and look for compilation warnings',
177 'err_msg' => 'compile warnings exist',
178 'function' => \&compile_warnings,
182 'category' => 'build',
183 'subcategory' => 'client',
184 'detail' => 'binary exists',
185 'err_msg' => 'binary not found',
186 'function' => \&binary_exists,
187 'binary' => $fwknopCmd,
191 'category' => 'build security',
192 'subcategory' => 'client',
193 'detail' => 'Position Independent Executable (PIE)',
194 'err_msg' => 'non PIE binary (fwknop client)',
195 'function' => \&pie_binary,
196 'binary' => $fwknopCmd,
200 'category' => 'build security',
201 'subcategory' => 'client',
202 'detail' => 'stack protected binary',
203 'err_msg' => 'non stack protected binary (fwknop client)',
204 'function' => \&stack_protected_binary,
205 'binary' => $fwknopCmd,
209 'category' => 'build security',
210 'subcategory' => 'client',
211 'detail' => 'fortify source functions',
212 'err_msg' => 'source functions not fortified (fwknop client)',
213 'function' => \&fortify_source_functions,
214 'binary' => $fwknopCmd,
218 'category' => 'build security',
219 'subcategory' => 'client',
220 'detail' => 'read-only relocations',
221 'err_msg' => 'no read-only relocations (fwknop client)',
222 'function' => \&read_only_relocations,
223 'binary' => $fwknopCmd,
227 'category' => 'build security',
228 'subcategory' => 'client',
229 'detail' => 'immediate binding',
230 'err_msg' => 'no immediate binding (fwknop client)',
231 'function' => \&immediate_binding,
232 'binary' => $fwknopCmd,
237 'category' => 'build',
238 'subcategory' => 'server',
239 'detail' => 'binary exists',
240 'err_msg' => 'binary not found',
241 'function' => \&binary_exists,
242 'binary' => $fwknopdCmd,
247 'category' => 'build security',
248 'subcategory' => 'server',
249 'detail' => 'Position Independent Executable (PIE)',
250 'err_msg' => 'non PIE binary (fwknopd server)',
251 'function' => \&pie_binary,
252 'binary' => $fwknopdCmd,
256 'category' => 'build security',
257 'subcategory' => 'server',
258 'detail' => 'stack protected binary',
259 'err_msg' => 'non stack protected binary (fwknopd server)',
260 'function' => \&stack_protected_binary,
261 'binary' => $fwknopdCmd,
265 'category' => 'build security',
266 'subcategory' => 'server',
267 'detail' => 'fortify source functions',
268 'err_msg' => 'source functions not fortified (fwknopd server)',
269 'function' => \&fortify_source_functions,
270 'binary' => $fwknopdCmd,
274 'category' => 'build security',
275 'subcategory' => 'server',
276 'detail' => 'read-only relocations',
277 'err_msg' => 'no read-only relocations (fwknopd server)',
278 'function' => \&read_only_relocations,
279 'binary' => $fwknopdCmd,
283 'category' => 'build security',
284 'subcategory' => 'server',
285 'detail' => 'immediate binding',
286 'err_msg' => 'no immediate binding (fwknopd server)',
287 'function' => \&immediate_binding,
288 'binary' => $fwknopdCmd,
293 'category' => 'build',
294 'subcategory' => 'libfko',
295 'detail' => 'binary exists',
296 'err_msg' => 'binary not found',
297 'function' => \&binary_exists,
298 'binary' => $libfko_bin,
302 'category' => 'build security',
303 'subcategory' => 'libfko',
304 'detail' => 'stack protected binary',
305 'err_msg' => 'non stack protected binary (libfko)',
306 'function' => \&stack_protected_binary,
307 'binary' => $libfko_bin,
311 'category' => 'build security',
312 'subcategory' => 'libfko',
313 'detail' => 'fortify source functions',
314 'err_msg' => 'source functions not fortified (libfko)',
315 'function' => \&fortify_source_functions,
316 'binary' => $libfko_bin,
320 'category' => 'build security',
321 'subcategory' => 'libfko',
322 'detail' => 'read-only relocations',
323 'err_msg' => 'no read-only relocations (libfko)',
324 'function' => \&read_only_relocations,
325 'binary' => $libfko_bin,
329 'category' => 'build security',
330 'subcategory' => 'libfko',
331 'detail' => 'immediate binding',
332 'err_msg' => 'no immediate binding (libfko)',
333 'function' => \&immediate_binding,
334 'binary' => $libfko_bin,
339 'category' => 'preliminaries',
340 'subcategory' => 'client',
341 'detail' => 'usage info',
342 'err_msg' => 'could not get usage info',
343 'function' => \&generic_exec,
344 'cmdline' => "LD_LIBRARY_PATH=$lib_dir $valgrind_str $fwknopCmd -h",
348 'category' => 'preliminaries',
349 'subcategory' => 'client',
350 'detail' => 'getopt() no such argument',
351 'err_msg' => 'getopt() allowed non-existant argument',
352 'function' => \&generic_exec,
353 'cmdline' => "LD_LIBRARY_PATH=$lib_dir $valgrind_str $fwknopCmd --no-such-arg",
358 'category' => 'preliminaries',
359 'subcategory' => 'client',
360 'detail' => '--test mode, packet not sent',
361 'err_msg' => '--test mode, packet sent?',
362 'function' => \&generic_exec,
363 'positive_output_matches' => [qr/test\smode\senabled/],
364 'cmdline' => "$default_client_args --test",
369 'category' => 'preliminaries',
370 'subcategory' => 'client',
371 'detail' => 'expected code version',
372 'err_msg' => 'code version mis-match',
373 'function' => \&expected_code_version,
374 'cmdline' => "LD_LIBRARY_PATH=$lib_dir $valgrind_str $fwknopCmd --version",
379 'category' => 'preliminaries',
380 'subcategory' => 'server',
381 'detail' => 'usage info',
382 'err_msg' => 'could not get usage info',
383 'function' => \&generic_exec,
384 'cmdline' => "LD_LIBRARY_PATH=$lib_dir $valgrind_str $fwknopdCmd -h",
388 'category' => 'preliminaries',
389 'subcategory' => 'server',
390 'detail' => 'getopt() no such argument',
391 'err_msg' => 'getopt() allowed non-existant argument',
392 'function' => \&generic_exec,
393 'cmdline' => "LD_LIBRARY_PATH=$lib_dir $valgrind_str $fwknopdCmd --no-such-arg",
399 'category' => 'preliminaries',
400 'subcategory' => 'server',
401 'detail' => 'expected code version',
402 'err_msg' => 'code version mis-match',
403 'function' => \&expected_code_version,
404 'cmdline' => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
405 "$fwknopdCmd -c $default_conf -a " .
406 "$default_access_conf --version",
410 'category' => 'preliminaries',
411 'detail' => 'collecting system specifics',
412 'err_msg' => 'could not get complete system specs',
413 'function' => \&specs,
414 'binary' => $fwknopdCmd,
419 'category' => 'basic operations',
420 'detail' => 'dump config',
421 'err_msg' => 'could not dump configuration',
422 'function' => \&generic_exec,
423 'positive_output_matches' => [qr/SYSLOG_IDENTITY/],
425 'cmdline' => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
426 "$fwknopdCmd -c $default_conf " .
427 "-a $default_access_conf --dump-config",
431 'category' => 'basic operations',
432 'detail' => 'override config',
433 'err_msg' => 'could not override configuration',
434 'function' => \&generic_exec,
435 'positive_output_matches' => [qr/ENABLE_PCAP_PROMISC.*\'Y\'/],
437 'cmdline' => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
438 "$fwknopdCmd $default_server_conf_args " .
439 "-O $conf_dir/override_fwknopd.conf --dump-config",
444 'category' => 'basic operations',
445 'subcategory' => 'client',
446 'detail' => '--get-key path validation',
447 'err_msg' => 'accepted improper --get-key path',
448 'function' => \&generic_exec,
449 'positive_output_matches' => [qr/could\snot\sopen/i],
451 'cmdline' => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
452 "$fwknopCmd -A tcp/22 -s $fake_ip " .
453 "-D $loopback_ip --get-key not/there",
457 'category' => 'basic operations',
458 'subcategory' => 'client',
459 'detail' => 'require [-s|-R|-a]',
460 'err_msg' => 'allowed null allow IP',
461 'function' => \&generic_exec,
462 'positive_output_matches' => [qr/must\suse\sone\sof/i],
464 'cmdline' => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
465 "$fwknopCmd -D $loopback_ip",
469 'category' => 'basic operations',
470 'subcategory' => 'client',
471 'detail' => '--allow-ip <IP> valid IP',
472 'err_msg' => 'permitted invalid --allow-ip arg',
473 'function' => \&generic_exec,
474 'positive_output_matches' => [qr/Invalid\sallow\sIP\saddress/i],
476 'cmdline' => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
477 "$fwknopCmd -A tcp/22 -a invalidIP -D $loopback_ip",
481 'category' => 'basic operations',
482 'subcategory' => 'client',
483 'detail' => '-A <proto>/<port> specification',
484 'err_msg' => 'permitted invalid -A <proto>/<port>',
485 'function' => \&generic_exec,
486 'positive_output_matches' => [qr/Invalid\sSPA\saccess\smessage/i],
488 'cmdline' => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
489 "$fwknopCmd -A invalid/22 -a $fake_ip -D $loopback_ip",
493 'category' => 'basic operations',
494 'subcategory' => 'client',
495 'detail' => 'generate SPA packet',
496 'err_msg' => 'could not generate SPA packet',
497 'function' => \&client_send_spa_packet,
498 'cmdline' => $default_client_args,
503 'category' => 'basic operations',
504 'subcategory' => 'server',
505 'detail' => 'list current fwknopd fw rules',
506 'err_msg' => 'could not list current fwknopd fw rules',
507 'function' => \&generic_exec,
508 'cmdline' => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
509 "$fwknopdCmd $default_server_conf_args --fw-list",
513 'category' => 'basic operations',
514 'subcategory' => 'server',
515 'detail' => 'list all current fw rules',
516 'err_msg' => 'could not list all current fw rules',
517 'function' => \&generic_exec,
518 'cmdline' => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
519 "$fwknopdCmd $default_server_conf_args --fw-list-all",
523 'category' => 'basic operations',
524 'subcategory' => 'server',
525 'detail' => 'flush current firewall rules',
526 'err_msg' => 'could not flush current fw rules',
527 'function' => \&generic_exec,
528 'cmdline' => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
529 "$fwknopdCmd $default_server_conf_args --fw-flush",
534 'category' => 'basic operations',
535 'subcategory' => 'server',
537 'err_msg' => 'start error',
538 'function' => \&server_start,
539 'fwknopd_cmdline' => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
540 "$fwknopdCmd $default_server_conf_args $intf_str",
544 'category' => 'basic operations',
545 'subcategory' => 'server',
547 'err_msg' => 'stop error',
548 'function' => \&server_stop,
549 'fwknopd_cmdline' => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
550 "$fwknopdCmd $default_server_conf_args $intf_str",
554 'category' => 'basic operations',
555 'subcategory' => 'server',
556 'detail' => 'write PID',
557 'err_msg' => 'did not write PID',
558 'function' => \&write_pid,
559 'fwknopd_cmdline' => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
560 "$fwknopdCmd $default_server_conf_args $intf_str",
565 'category' => 'basic operations',
566 'subcategory' => 'server',
567 'detail' => '--packet-limit 1 exit',
568 'err_msg' => 'did not exit after one packet',
569 'function' => \&server_packet_limit,
570 'fwknopd_cmdline' => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
571 "$fwknopdCmd $default_server_conf_args --packet-limit 1 $intf_str",
575 'category' => 'basic operations',
576 'subcategory' => 'server',
577 'detail' => 'ignore packets < min SPA len (140)',
578 'err_msg' => 'did not ignore small packets',
579 'function' => \&server_ignore_small_packets,
580 'fwknopd_cmdline' => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
581 "$fwknopdCmd $default_server_conf_args --packet-limit 1 $intf_str",
585 'category' => 'basic operations',
586 'subcategory' => 'server',
587 'detail' => '-P bpf filter ignore packet',
588 'err_msg' => 'filter did not ignore packet',
589 'function' => \&server_bpf_ignore_packet,
590 'cmdline' => $default_client_args,
591 'fwknopd_cmdline' => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
592 "$fwknopdCmd $default_server_conf_args --packet-limit 1 $intf_str " .
593 qq|-P "udp port $non_std_spa_port"|,
598 'category' => 'Rijndael SPA',
599 'subcategory' => 'client+server',
600 'detail' => 'complete cycle (tcp/22 ssh)',
601 'err_msg' => 'could not complete SPA cycle',
602 'function' => \&spa_cycle,
603 'cmdline' => $default_client_args,
604 'fwknopd_cmdline' => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
605 "$fwknopdCmd $default_server_conf_args $intf_str",
606 'fw_rule_created' => $NEW_RULE_REQUIRED,
607 'fw_rule_removed' => $NEW_RULE_REMOVED,
611 'category' => 'Rijndael SPA',
612 'subcategory' => 'client+server',
613 'detail' => 'dual usage access key (tcp/80 http)',
614 'err_msg' => 'could not complete SPA cycle',
615 'function' => \&spa_cycle,
616 'cmdline' => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
617 "$fwknopCmd -A tcp/80 -a $fake_ip -D $loopback_ip --get-key " .
618 "$local_key_file --verbose --verbose",
619 'fwknopd_cmdline' => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
620 "$fwknopdCmd -c $default_conf -a $dual_key_usage_access_conf " .
621 "-d $default_digest_file -p $default_pid_file $intf_str",
622 ### check for the first stanza that does not allow tcp/80 - the
623 ### second stanza allows this
624 'server_positive_output_matches' => [qr/stanza #1\)\sOne\sor\smore\srequested\sprotocol\/ports\swas\sdenied/],
625 'fw_rule_created' => $NEW_RULE_REQUIRED,
626 'fw_rule_removed' => $NEW_RULE_REMOVED,
630 'category' => 'Rijndael SPA',
631 'subcategory' => 'client+server',
632 'detail' => 'packet aging (past) (tcp/22 ssh)',
633 'err_msg' => 'old SPA packet accepted',
634 'function' => \&spa_cycle,
635 'cmdline' => "$default_client_args --time-offset-minus 300s",
636 'fwknopd_cmdline' => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
637 "$fwknopdCmd $default_server_conf_args $intf_str",
638 'server_positive_output_matches' => [qr/SPA\sdata\stime\sdifference/],
639 'fw_rule_created' => $REQUIRE_NO_NEW_RULE,
643 'category' => 'Rijndael SPA',
644 'subcategory' => 'client+server',
645 'detail' => 'packet aging (future) (tcp/22 ssh)',
646 'err_msg' => 'future SPA packet accepted',
647 'function' => \&spa_cycle,
648 'cmdline' => "$default_client_args --time-offset-plus 300s",
649 'fwknopd_cmdline' => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
650 "$fwknopdCmd $default_server_conf_args $intf_str",
651 'server_positive_output_matches' => [qr/SPA\sdata\stime\sdifference/],
652 'fw_rule_created' => $REQUIRE_NO_NEW_RULE,
656 'category' => 'Rijndael SPA',
657 'subcategory' => 'client+server',
658 'detail' => 'invalid SOURCE (tcp/22 ssh)',
659 'err_msg' => 'SPA packet accepted',
660 'function' => \&spa_cycle,
661 'cmdline' => $default_client_args,
662 'fwknopd_cmdline' => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
663 "$fwknopdCmd -c $default_conf -a $invalid_source_access_conf " .
664 "-d $default_digest_file -p $default_pid_file $intf_str",
665 'server_positive_output_matches' => [qr/Fatal\serror\sparsing\sIP\sto\sint/],
666 'fw_rule_created' => $REQUIRE_NO_NEW_RULE,
670 'category' => 'Rijndael SPA',
671 'subcategory' => 'client+server',
672 'detail' => 'expired stanza (tcp/22 ssh)',
673 'err_msg' => 'SPA packet accepted',
674 'function' => \&spa_cycle,
675 'cmdline' => $default_client_args,
676 'fwknopd_cmdline' => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
677 "$fwknopdCmd -c $default_conf -a $expired_access_conf " .
678 "-d $default_digest_file -p $default_pid_file $intf_str",
679 'server_positive_output_matches' => [qr/Access\sstanza\shas\sexpired/],
680 'fw_rule_created' => $REQUIRE_NO_NEW_RULE,
684 'category' => 'Rijndael SPA',
685 'subcategory' => 'client+server',
686 'detail' => 'invalid expire date (tcp/22 ssh)',
687 'err_msg' => 'SPA packet accepted',
688 'function' => \&spa_cycle,
689 'cmdline' => $default_client_args,
690 'fwknopd_cmdline' => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
691 "$fwknopdCmd -c $default_conf -a $invalid_expire_access_conf " .
692 "-d $default_digest_file -p $default_pid_file $intf_str",
693 'server_positive_output_matches' => [qr/invalid\sdate\svalue/],
694 'fw_rule_created' => $REQUIRE_NO_NEW_RULE,
698 'category' => 'Rijndael SPA',
699 'subcategory' => 'client+server',
700 'detail' => 'expired epoch stanza (tcp/22 ssh)',
701 'err_msg' => 'SPA packet accepted',
702 'function' => \&spa_cycle,
703 'cmdline' => $default_client_args,
704 'fwknopd_cmdline' => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
705 "$fwknopdCmd -c $default_conf -a $expired_epoch_access_conf " .
706 "-d $default_digest_file -p $default_pid_file $intf_str",
707 'server_positive_output_matches' => [qr/Access\sstanza\shas\sexpired/],
708 'fw_rule_created' => $REQUIRE_NO_NEW_RULE,
712 'category' => 'Rijndael SPA',
713 'subcategory' => 'client+server',
714 'detail' => 'future expired stanza (tcp/22 ssh)',
715 'err_msg' => 'SPA packet not accepted',
716 'function' => \&spa_cycle,
717 'cmdline' => $default_client_args,
718 'fwknopd_cmdline' => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
719 "$fwknopdCmd -c $default_conf -a $future_expired_access_conf " .
720 "-d $default_digest_file -p $default_pid_file $intf_str",
721 'fw_rule_created' => $NEW_RULE_REQUIRED,
722 'fw_rule_removed' => $NEW_RULE_REMOVED,
727 'category' => 'Rijndael SPA',
728 'subcategory' => 'client+server',
729 'detail' => 'OPEN_PORTS (tcp/22 ssh)',
730 'err_msg' => "improper OPEN_PORTS result",
731 'function' => \&spa_cycle,
732 'cmdline' => $default_client_args,
733 'fwknopd_cmdline' => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
734 "$fwknopdCmd -c $default_conf -a $open_ports_access_conf " .
735 "-d $default_digest_file -p $default_pid_file $intf_str",
736 'fw_rule_created' => $NEW_RULE_REQUIRED,
737 'fw_rule_removed' => $NEW_RULE_REMOVED,
741 'category' => 'Rijndael SPA',
742 'subcategory' => 'client+server',
743 'detail' => 'OPEN_PORTS mismatch',
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 $default_conf -a $mismatch_open_ports_access_conf " .
749 "-d $default_digest_file -p $default_pid_file $intf_str",
750 'server_positive_output_matches' => [qr/One\s+or\s+more\s+requested/],
751 'fw_rule_created' => $REQUIRE_NO_NEW_RULE,
755 'category' => 'Rijndael SPA',
756 'subcategory' => 'client+server',
757 'detail' => 'require user (tcp/22 ssh)',
758 'err_msg' => "missed require user criteria",
759 'function' => \&spa_cycle,
760 'cmdline' => "SPOOF_USER=$spoof_user $default_client_args",
761 'fwknopd_cmdline' => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
762 "$fwknopdCmd -c $default_conf -a $require_user_access_conf " .
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,
769 'category' => 'Rijndael SPA',
770 'subcategory' => 'client+server',
771 'detail' => 'user mismatch (tcp/22 ssh)',
772 'err_msg' => "improper user accepted for access",
773 'function' => \&user_mismatch,
774 'function' => \&spa_cycle,
775 'cmdline' => $default_client_args,
776 'fwknopd_cmdline' => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
777 "$fwknopdCmd -c $default_conf -a $mismatch_user_access_conf " .
778 "-d $default_digest_file -p $default_pid_file $intf_str",
779 'server_positive_output_matches' => [qr/Username\s+in\s+SPA\s+data/],
780 'fw_rule_created' => $REQUIRE_NO_NEW_RULE,
784 'category' => 'Rijndael SPA',
785 'subcategory' => 'client+server',
786 'detail' => 'require src (tcp/22 ssh)',
787 'err_msg' => "fw rule not created",
788 'function' => \&spa_cycle,
789 'cmdline' => $default_client_args,
790 'fwknopd_cmdline' => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
791 "$fwknopdCmd -c $default_conf -a $require_src_access_conf " .
792 "-d $default_digest_file -p $default_pid_file $intf_str",
793 'fw_rule_created' => $NEW_RULE_REQUIRED,
794 'fw_rule_removed' => $NEW_RULE_REMOVED,
798 'category' => 'Rijndael SPA',
799 'subcategory' => 'client+server',
800 'detail' => 'mismatch require src (tcp/22 ssh)',
801 'err_msg' => "fw rule created",
802 'function' => \&spa_cycle,
803 'cmdline' => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
804 "$fwknopCmd -A tcp/22 -s -D $loopback_ip --get-key " .
805 "$local_key_file --verbose --verbose",
806 'fwknopd_cmdline' => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
807 "$fwknopdCmd -c $default_conf -a $require_src_access_conf " .
808 "-d $default_digest_file -p $default_pid_file $intf_str",
809 'server_positive_output_matches' => [qr/Got\s0.0.0.0\swhen\svalid\ssource\sIP/],
810 'fw_rule_created' => $REQUIRE_NO_NEW_RULE,
815 'category' => 'Rijndael SPA',
816 'subcategory' => 'client+server',
817 'detail' => 'IP filtering (tcp/22 ssh)',
818 'err_msg' => "did not filter $loopback_ip",
819 'function' => \&spa_cycle,
820 'cmdline' => $default_client_args,
821 'fwknopd_cmdline' => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
822 "$fwknopdCmd -c $default_conf -a $no_source_match_access_conf " .
823 "-d $default_digest_file -p $default_pid_file $intf_str",
824 'server_positive_output_matches' => [qr/No\saccess\sdata\sfound/],
825 'fw_rule_created' => $REQUIRE_NO_NEW_RULE,
829 'category' => 'Rijndael SPA',
830 'subcategory' => 'client+server',
831 'detail' => 'subnet filtering (tcp/22 ssh)',
832 'err_msg' => "did not filter $loopback_ip",
833 'function' => \&spa_cycle,
834 'cmdline' => $default_client_args,
835 'fwknopd_cmdline' => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
836 "$fwknopdCmd -c $default_conf -a $no_subnet_source_match_access_conf " .
837 "-d $default_digest_file -p $default_pid_file $intf_str",
838 'server_positive_output_matches' => [qr/No\saccess\sdata\sfound/],
839 'fw_rule_created' => $REQUIRE_NO_NEW_RULE,
843 'category' => 'Rijndael SPA',
844 'subcategory' => 'client+server',
845 'detail' => 'IP+subnet filtering (tcp/22 ssh)',
846 'err_msg' => "did not filter $loopback_ip",
847 'function' => \&spa_cycle,
848 'cmdline' => $default_client_args,
849 'fwknopd_cmdline' => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
850 "$fwknopdCmd -c $default_conf -a $no_multi_source_match_access_conf " .
851 "-d $default_digest_file -p $default_pid_file $intf_str",
852 'server_positive_output_matches' => [qr/No\saccess\sdata\sfound/],
853 'fw_rule_created' => $REQUIRE_NO_NEW_RULE,
857 'category' => 'Rijndael SPA',
858 'subcategory' => 'client+server',
859 'detail' => 'IP match (tcp/22 ssh)',
860 'err_msg' => "did not filter $loopback_ip",
861 'function' => \&spa_cycle,
862 'cmdline' => $default_client_args,
863 'fwknopd_cmdline' => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
864 "$fwknopdCmd -c $default_conf -a $ip_source_match_access_conf " .
865 "-d $default_digest_file -p $default_pid_file $intf_str",
866 'fw_rule_created' => $NEW_RULE_REQUIRED,
867 'fw_rule_removed' => $NEW_RULE_REMOVED,
871 'category' => 'Rijndael SPA',
872 'subcategory' => 'client+server',
873 'detail' => 'subnet match (tcp/22 ssh)',
874 'err_msg' => "did not filter $loopback_ip",
875 'function' => \&spa_cycle,
876 'cmdline' => $default_client_args,
877 'fwknopd_cmdline' => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
878 "$fwknopdCmd -c $default_conf -a $subnet_source_match_access_conf " .
879 "-d $default_digest_file -p $default_pid_file $intf_str",
880 'fw_rule_created' => $NEW_RULE_REQUIRED,
881 'fw_rule_removed' => $NEW_RULE_REMOVED,
885 'category' => 'Rijndael SPA',
886 'subcategory' => 'client+server',
887 'detail' => 'multi IP/net match (tcp/22 ssh)',
888 'err_msg' => "did not filter $loopback_ip",
889 'function' => \&spa_cycle,
890 'cmdline' => $default_client_args,
891 'fwknopd_cmdline' => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
892 "$fwknopdCmd -c $default_conf -a $multi_source_match_access_conf " .
893 "-d $default_digest_file -p $default_pid_file $intf_str",
894 'fw_rule_created' => $NEW_RULE_REQUIRED,
895 'fw_rule_removed' => $NEW_RULE_REMOVED,
899 'category' => 'Rijndael SPA',
900 'subcategory' => 'client+server',
901 'detail' => 'multi access stanzas (tcp/22 ssh)',
902 'err_msg' => "could not complete SPA cycle",
903 'function' => \&spa_cycle,
904 'cmdline' => $default_client_args,
905 'fwknopd_cmdline' => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
906 "$fwknopdCmd -c $default_conf -a $multi_stanzas_access_conf " .
907 "-d $default_digest_file -p $default_pid_file $intf_str",
908 'fw_rule_created' => $NEW_RULE_REQUIRED,
909 'fw_rule_removed' => $NEW_RULE_REMOVED,
913 'category' => 'Rijndael SPA',
914 'subcategory' => 'client+server',
915 'detail' => 'bad/good key stanzas (tcp/22 ssh)',
916 'err_msg' => "could not complete SPA cycle",
917 'function' => \&spa_cycle,
918 'cmdline' => $default_client_args,
919 'fwknopd_cmdline' => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
920 "$fwknopdCmd -c $default_conf -a $multi_stanzas_with_broken_keys_conf " .
921 "-d $default_digest_file -p $default_pid_file $intf_str",
922 'fw_rule_created' => $NEW_RULE_REQUIRED,
923 'fw_rule_removed' => $NEW_RULE_REMOVED,
928 'category' => 'Rijndael SPA',
929 'subcategory' => 'client+server',
930 'detail' => "non-enabled NAT (tcp/22 ssh)",
931 'err_msg' => "SPA packet not filtered",
932 'function' => \&spa_cycle,
933 'cmdline' => "$default_client_args -N $internal_nat_host:22",
934 'fwknopd_cmdline' => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
935 "$fwknopdCmd $default_server_conf_args $intf_str",
936 'server_positive_output_matches' => [qr/requested\sNAT\saccess.*not\senabled/i],
937 'server_conf' => $nat_conf,
938 'fw_rule_created' => $REQUIRE_NO_NEW_RULE,
942 'category' => 'Rijndael SPA',
943 'subcategory' => 'client+server',
944 'detail' => "NAT to $internal_nat_host (tcp/22 ssh)",
945 'err_msg' => "could not complete NAT SPA cycle",
946 'function' => \&spa_cycle,
947 'cmdline' => "$default_client_args -N $internal_nat_host:22",
948 'fwknopd_cmdline' => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
949 "$fwknopdCmd -c $nat_conf -a $open_ports_access_conf " .
950 "-d $default_digest_file -p $default_pid_file $intf_str",
951 'server_positive_output_matches' => [qr/to\:$internal_nat_host\:22/i],
952 'fw_rule_created' => $NEW_RULE_REQUIRED,
953 'fw_rule_removed' => $NEW_RULE_REMOVED,
954 'server_conf' => $nat_conf,
959 'category' => 'Rijndael SPA',
960 'subcategory' => 'client+server',
961 'detail' => "force NAT $force_nat_host (tcp/22 ssh)",
962 'err_msg' => "could not complete NAT SPA cycle",
963 'function' => \&spa_cycle,
964 'cmdline' => $default_client_args,
965 'fwknopd_cmdline' => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
966 "$fwknopdCmd -c $nat_conf -a $force_nat_access_conf " .
967 "-d $default_digest_file -p $default_pid_file $intf_str",
968 'server_positive_output_matches' => [qr/to\:$force_nat_host\:22/i],
969 'server_negative_output_matches' => [qr/to\:$internal_nat_host\:22/i],
970 'fw_rule_created' => $NEW_RULE_REQUIRED,
971 'fw_rule_removed' => $NEW_RULE_REMOVED,
972 'server_conf' => $nat_conf,
976 'category' => 'Rijndael SPA',
977 'subcategory' => 'client+server',
978 'detail' => 'ECB mode (tcp/22 ssh)',
979 'err_msg' => 'could not complete SPA cycle',
980 'function' => \&spa_cycle,
981 'cmdline' => "$default_client_args -M ecb",
982 'fwknopd_cmdline' => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
983 "$fwknopdCmd -c $default_conf -a $ecb_mode_access_conf " .
984 "-d $default_digest_file -p $default_pid_file $intf_str",
985 'server_negative_output_matches' => [qr/Decryption\sfailed/i],
986 'fw_rule_created' => $NEW_RULE_REQUIRED,
987 'fw_rule_removed' => $NEW_RULE_REMOVED,
991 'category' => 'Rijndael SPA',
992 'subcategory' => 'client+server',
993 'detail' => 'CFB mode (tcp/22 ssh)',
994 'err_msg' => 'could not complete SPA cycle',
995 'function' => \&spa_cycle,
996 'cmdline' => "$default_client_args -M cfb",
997 'fwknopd_cmdline' => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
998 "$fwknopdCmd -c $default_conf -a $cfb_mode_access_conf " .
999 "-d $default_digest_file -p $default_pid_file $intf_str",
1000 'server_negative_output_matches' => [qr/Decryption\sfailed/i],
1001 'fw_rule_created' => $NEW_RULE_REQUIRED,
1002 'fw_rule_removed' => $NEW_RULE_REMOVED,
1006 'category' => 'Rijndael SPA',
1007 'subcategory' => 'client+server',
1008 'detail' => 'CTR mode (tcp/22 ssh)',
1009 'err_msg' => 'could not complete SPA cycle',
1010 'function' => \&spa_cycle,
1011 'cmdline' => "$default_client_args -M ctr",
1012 'fwknopd_cmdline' => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
1013 "$fwknopdCmd -c $default_conf -a $ctr_mode_access_conf " .
1014 "-d $default_digest_file -p $default_pid_file $intf_str",
1015 'server_negative_output_matches' => [qr/Decryption\sfailed/i],
1016 'fw_rule_created' => $NEW_RULE_REQUIRED,
1017 'fw_rule_removed' => $NEW_RULE_REMOVED,
1021 'category' => 'Rijndael SPA',
1022 'subcategory' => 'client+server',
1023 'detail' => 'OFB mode (tcp/22 ssh)',
1024 'err_msg' => 'could not complete SPA cycle',
1025 'function' => \&spa_cycle,
1026 'cmdline' => "$default_client_args -M ofb",
1027 'fwknopd_cmdline' => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
1028 "$fwknopdCmd -c $default_conf -a $ofb_mode_access_conf " .
1029 "-d $default_digest_file -p $default_pid_file $intf_str",
1030 'server_negative_output_matches' => [qr/Decryption\sfailed/i],
1031 'fw_rule_created' => $NEW_RULE_REQUIRED,
1032 'fw_rule_removed' => $NEW_RULE_REMOVED,
1037 'category' => 'Rijndael SPA',
1038 'subcategory' => 'client+server',
1039 'detail' => 'mode mismatch (tcp/22 ssh)',
1040 'err_msg' => 'server accepted mismatch enc mode',
1041 'function' => \&spa_cycle,
1042 'cmdline' => "$default_client_args -M ecb",
1043 'fwknopd_cmdline' => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
1044 "$fwknopdCmd -c $default_conf -a $default_access_conf " .
1045 "-d $default_digest_file -p $default_pid_file $intf_str",
1046 'server_positive_output_matches' => [qr/Decryption\sfailed/i],
1047 'fw_rule_created' => $REQUIRE_NO_NEW_RULE,
1052 'category' => 'Rijndael SPA',
1053 'subcategory' => 'client+server',
1054 'detail' => 'complete cycle (tcp/23 telnet)',
1055 'err_msg' => 'could not complete SPA cycle',
1056 'function' => \&spa_cycle,
1057 'cmdline' => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
1058 "$fwknopCmd -A tcp/23 -a $fake_ip -D $loopback_ip --get-key " .
1059 "$local_key_file --verbose --verbose",
1060 'fwknopd_cmdline' => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
1061 "$fwknopdCmd $default_server_conf_args $intf_str",
1062 'fw_rule_created' => $NEW_RULE_REQUIRED,
1063 'fw_rule_removed' => $NEW_RULE_REMOVED,
1067 'category' => 'Rijndael SPA',
1068 'subcategory' => 'client+server',
1069 'detail' => 'complete cycle (tcp/9418 git)',
1070 'err_msg' => 'could not complete SPA cycle',
1071 'function' => \&spa_cycle,
1072 'cmdline' => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
1073 "$fwknopCmd -A tcp/9418 -a $fake_ip -D $loopback_ip --get-key " .
1074 "$local_key_file --verbose --verbose",
1075 'fwknopd_cmdline' => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
1076 "$fwknopdCmd $default_server_conf_args $intf_str",
1077 'fw_rule_created' => $NEW_RULE_REQUIRED,
1078 'fw_rule_removed' => $NEW_RULE_REMOVED,
1082 'category' => 'Rijndael SPA',
1083 'subcategory' => 'client+server',
1084 'detail' => 'complete cycle (udp/53 dns)',
1085 'err_msg' => 'could not complete SPA cycle',
1086 'function' => \&spa_cycle,
1087 'cmdline' => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
1088 "$fwknopCmd -A udp/53 -a $fake_ip -D $loopback_ip --get-key " .
1089 "$local_key_file --verbose --verbose",
1090 'fwknopd_cmdline' => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
1091 "$fwknopdCmd $default_server_conf_args $intf_str",
1092 'fw_rule_created' => $NEW_RULE_REQUIRED,
1093 'fw_rule_removed' => $NEW_RULE_REMOVED,
1097 'category' => 'Rijndael SPA',
1098 'subcategory' => 'client+server',
1099 'detail' => "-P bpf SPA over port $non_std_spa_port",
1100 'err_msg' => 'could not complete SPA cycle',
1101 'function' => \&spa_cycle,
1102 'cmdline' => "$default_client_args --server-port $non_std_spa_port",
1103 'fwknopd_cmdline' => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
1104 "$fwknopdCmd $default_server_conf_args $intf_str " .
1105 qq|-P "udp port $non_std_spa_port"|,
1106 'server_positive_output_matches' => [qr/PCAP\sfilter.*\s$non_std_spa_port/],
1107 'fw_rule_created' => $NEW_RULE_REQUIRED,
1108 'fw_rule_removed' => $NEW_RULE_REMOVED,
1113 'category' => 'Rijndael SPA',
1114 'subcategory' => 'client+server',
1115 'detail' => 'random SPA port (tcp/22 ssh)',
1116 'err_msg' => 'could not complete SPA cycle',
1117 'function' => \&spa_cycle,
1118 'cmdline' => "$default_client_args -r",
1119 'fwknopd_cmdline' => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
1120 "$fwknopdCmd $default_server_conf_args $intf_str " .
1122 'fw_rule_created' => $NEW_RULE_REQUIRED,
1123 'fw_rule_removed' => $NEW_RULE_REMOVED,
1128 'category' => 'Rijndael SPA',
1129 'subcategory' => 'client+server',
1130 'detail' => 'spoof username (tcp/22)',
1131 'err_msg' => 'could not spoof username',
1132 'function' => \&spoof_username,
1133 'cmdline' => "SPOOF_USER=$spoof_user LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
1134 "$fwknopCmd -A tcp/22 -a $fake_ip -D $loopback_ip --get-key " .
1135 "$local_key_file --verbose --verbose",
1136 'fwknopd_cmdline' => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
1137 "$fwknopdCmd $default_server_conf_args $intf_str",
1142 'category' => 'Rijndael SPA',
1143 'subcategory' => 'client+server',
1144 'detail' => 'replay attack detection',
1145 'err_msg' => 'could not detect replay attack',
1146 'function' => \&replay_detection,
1147 'cmdline' => $default_client_args,
1148 'fwknopd_cmdline' => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
1149 "$fwknopdCmd $default_server_conf_args $intf_str",
1153 'category' => 'Rijndael SPA',
1154 'subcategory' => 'server',
1155 'detail' => 'digest cache structure',
1156 'err_msg' => 'improper digest cache structure',
1157 'function' => \&digest_cache_structure,
1162 'category' => 'Rijndael SPA',
1163 'subcategory' => 'client+server',
1164 'detail' => 'non-base64 altered SPA data',
1165 'err_msg' => 'allowed improper SPA data',
1166 'function' => \&altered_non_base64_spa_data,
1167 'cmdline' => $default_client_args,
1168 'fwknopd_cmdline' => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
1169 "$fwknopdCmd $default_server_conf_args $intf_str",
1173 'category' => 'Rijndael SPA',
1174 'subcategory' => 'client+server',
1175 'detail' => 'base64 altered SPA data',
1176 'err_msg' => 'allowed improper SPA data',
1177 'function' => \&altered_base64_spa_data,
1178 'cmdline' => $default_client_args,
1179 'fwknopd_cmdline' => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
1180 "$fwknopdCmd $default_server_conf_args $intf_str",
1184 'category' => 'Rijndael SPA',
1185 'subcategory' => 'client+server',
1186 'detail' => 'appended data to SPA pkt',
1187 'err_msg' => 'allowed improper SPA data',
1188 'function' => \&appended_spa_data,
1189 'cmdline' => $default_client_args,
1190 'fwknopd_cmdline' => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
1191 "$fwknopdCmd $default_server_conf_args $intf_str",
1195 'category' => 'Rijndael SPA',
1196 'subcategory' => 'client+server',
1197 'detail' => 'prepended data to SPA pkt',
1198 'err_msg' => 'allowed improper SPA data',
1199 'function' => \&prepended_spa_data,
1200 'cmdline' => $default_client_args,
1201 'fwknopd_cmdline' => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
1202 "$fwknopdCmd $default_server_conf_args $intf_str",
1207 'category' => 'GnuPG (GPG) SPA',
1208 'subcategory' => 'client+server',
1209 'detail' => 'complete cycle (tcp/22 ssh)',
1210 'err_msg' => 'could not complete SPA cycle',
1211 'function' => \&spa_cycle,
1212 'cmdline' => $default_client_gpg_args,
1213 'fwknopd_cmdline' => $default_server_gpg_args,
1214 'fw_rule_created' => $NEW_RULE_REQUIRED,
1215 'fw_rule_removed' => $NEW_RULE_REMOVED,
1219 'category' => 'GnuPG (GPG) SPA',
1220 'subcategory' => 'client+server',
1221 'detail' => 'multi gpg-IDs (tcp/22 ssh)',
1222 'err_msg' => 'could not complete SPA cycle',
1223 'function' => \&spa_cycle,
1224 'cmdline' => $default_client_gpg_args,
1225 'fwknopd_cmdline' => "LD_LIBRARY_PATH=$lib_dir " .
1226 "$valgrind_str $fwknopdCmd -c $default_conf " .
1227 "-a $multi_gpg_access_conf $intf_str " .
1228 "-d $default_digest_file -p $default_pid_file",
1229 'fw_rule_created' => $NEW_RULE_REQUIRED,
1230 'fw_rule_removed' => $NEW_RULE_REMOVED,
1235 'category' => 'GnuPG (GPG) SPA',
1236 'subcategory' => 'client+server',
1237 'detail' => 'complete cycle (tcp/23 telnet)',
1238 'err_msg' => 'could not complete SPA cycle',
1239 'function' => \&spa_cycle,
1240 'cmdline' => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
1241 "$fwknopCmd -A tcp/23 -a $fake_ip -D $loopback_ip --get-key " .
1242 "$local_key_file --verbose --verbose " .
1243 "--gpg-recipient-key $gpg_server_key " .
1244 "--gpg-signer-key $gpg_client_key " .
1245 "--gpg-home-dir $gpg_client_home_dir",
1246 'fwknopd_cmdline' => $default_server_gpg_args,
1247 'fw_rule_created' => $NEW_RULE_REQUIRED,
1248 'fw_rule_removed' => $NEW_RULE_REMOVED,
1252 'category' => 'GnuPG (GPG) SPA',
1253 'subcategory' => 'client+server',
1254 'detail' => 'complete cycle (tcp/9418 git)',
1255 'err_msg' => 'could not complete SPA cycle',
1256 'function' => \&spa_cycle,
1257 'cmdline' => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
1258 "$fwknopCmd -A tcp/9418 -a $fake_ip -D $loopback_ip --get-key " .
1259 "$local_key_file --verbose --verbose " .
1260 "--gpg-recipient-key $gpg_server_key " .
1261 "--gpg-signer-key $gpg_client_key " .
1262 "--gpg-home-dir $gpg_client_home_dir",
1263 'fwknopd_cmdline' => $default_server_gpg_args,
1264 'fw_rule_created' => $NEW_RULE_REQUIRED,
1265 'fw_rule_removed' => $NEW_RULE_REMOVED,
1269 'category' => 'GnuPG (GPG) SPA',
1270 'subcategory' => 'client+server',
1271 'detail' => 'complete cycle (udp/53 dns)',
1272 'err_msg' => 'could not complete SPA cycle',
1273 'function' => \&spa_cycle,
1274 'cmdline' => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
1275 "$fwknopCmd -A udp/53 -a $fake_ip -D $loopback_ip --get-key " .
1276 "$local_key_file --verbose --verbose " .
1277 "--gpg-recipient-key $gpg_server_key " .
1278 "--gpg-signer-key $gpg_client_key " .
1279 "--gpg-home-dir $gpg_client_home_dir",
1280 'fwknopd_cmdline' => $default_server_gpg_args,
1281 'fw_rule_created' => $NEW_RULE_REQUIRED,
1282 'fw_rule_removed' => $NEW_RULE_REMOVED,
1287 'category' => 'GnuPG (GPG) SPA',
1288 'subcategory' => 'client+server',
1289 'detail' => 'replay attack detection',
1290 'err_msg' => 'could not detect replay attack',
1291 'function' => \&replay_detection,
1292 'cmdline' => $default_client_gpg_args,
1293 'fwknopd_cmdline' => $default_server_gpg_args,
1298 'category' => 'GnuPG (GPG) SPA',
1299 'subcategory' => 'client+server',
1300 'detail' => 'non-base64 altered SPA data',
1301 'err_msg' => 'allowed improper SPA data',
1302 'function' => \&altered_non_base64_spa_data,
1303 'cmdline' => $default_client_gpg_args,
1304 'fwknopd_cmdline' => $default_server_gpg_args,
1308 'category' => 'GnuPG (GPG) SPA',
1309 'subcategory' => 'client+server',
1310 'detail' => 'base64 altered SPA data',
1311 'err_msg' => 'allowed improper SPA data',
1312 'function' => \&altered_base64_spa_data,
1313 'cmdline' => $default_client_gpg_args,
1314 'fwknopd_cmdline' => $default_server_gpg_args,
1318 'category' => 'GnuPG (GPG) SPA',
1319 'subcategory' => 'client+server',
1320 'detail' => 'appended data to SPA pkt',
1321 'err_msg' => 'allowed improper SPA data',
1322 'function' => \&appended_spa_data,
1323 'cmdline' => $default_client_gpg_args,
1324 'fwknopd_cmdline' => $default_server_gpg_args,
1328 'category' => 'GnuPG (GPG) SPA',
1329 'subcategory' => 'client+server',
1330 'detail' => 'prepended data to SPA pkt',
1331 'err_msg' => 'allowed improper SPA data',
1332 'function' => \&prepended_spa_data,
1333 'cmdline' => $default_client_gpg_args,
1334 'fwknopd_cmdline' => $default_server_gpg_args,
1338 'category' => 'GnuPG (GPG) SPA',
1339 'subcategory' => 'client+server',
1340 'detail' => 'spoof username (tcp/22 ssh)',
1341 'err_msg' => 'could not spoof username',
1342 'function' => \&spoof_username,
1343 'cmdline' => "SPOOF_USER=$spoof_user $default_client_gpg_args",
1344 'fwknopd_cmdline' => $default_server_gpg_args,
1348 'category' => 'GnuPG (GPG) SPA',
1349 'subcategory' => 'server',
1350 'detail' => 'digest cache structure',
1351 'err_msg' => 'improper digest cache structure',
1352 'function' => \&digest_cache_structure,
1357 'category' => 'profile coverage',
1358 'detail' => 'gcov profile coverage',
1359 'err_msg' => 'profile coverage failed',
1360 'function' => \&profile_coverage,
1365 if ($use_valgrind) {
1368 'category' => 'valgrind output',
1369 'subcategory' => 'flagged functions',
1371 'err_msg' => 'could not parse flagged functions',
1372 'function' => \&parse_valgrind_flagged_functions,
1378 'category' => $REQUIRED,
1379 'subcategory' => $OPTIONAL,
1380 'detail' => $REQUIRED,
1381 'function' => $REQUIRED,
1382 'binary' => $OPTIONAL,
1383 'cmdline' => $OPTIONAL,
1384 'fwknopd_cmdline' => $OPTIONAL,
1385 'fatal' => $OPTIONAL,
1386 'exec_err' => $OPTIONAL,
1387 'fw_rule_created' => $OPTIONAL,
1388 'fw_rule_removed' => $OPTIONAL,
1389 'server_conf' => $OPTIONAL,
1390 'positive_output_matches' => $OPTIONAL,
1391 'negative_output_matches' => $OPTIONAL,
1392 'server_positive_output_matches' => $OPTIONAL,
1393 'server_negative_output_matches' => $OPTIONAL,
1397 &diff_test_results();
1401 ### make sure everything looks as expected before continuing
1404 &logr("\n[+] Starting the fwknop test suite...\n\n" .
1405 " args: @args_cp\n\n"
1408 ### save the results from any previous test suite run
1409 ### so that we can potentially compare them with --diff
1410 if ($saved_last_results) {
1411 &logr(" Saved results from previous run " .
1412 "to: ${output_dir}.last/\n\n");
1415 ### main loop through all of the tests
1416 for my $test_hr (@tests) {
1417 &run_test($test_hr);
1420 &logr("\n[+] passed/failed/executed: $passed/$failed/$executed tests\n\n");
1422 copy $logfile, "$output_dir/$logfile" or die $!;
1426 #===================== end main =======================
1429 my $test_hr = shift;
1431 my $msg = "[$test_hr->{'category'}]";
1432 $msg .= " [$test_hr->{'subcategory'}]" if $test_hr->{'subcategory'};
1433 $msg .= " $test_hr->{'detail'}";
1435 return unless &process_include_exclude($msg);
1445 $current_test_file = "$output_dir/$executed.test";
1446 $server_test_file = "$output_dir/${executed}_fwknopd.test";
1448 &write_test_file("[+] TEST: $msg\n", $current_test_file);
1449 $test_hr->{'msg'} = $msg;
1450 if (&{$test_hr->{'function'}}($test_hr)) {
1451 &logr("pass ($executed)\n");
1454 &logr("fail ($executed)\n");
1457 if ($test_hr->{'fatal'} eq $YES) {
1458 die "[*] required test failed, exiting.";
1465 sub process_include_exclude() {
1468 ### inclusions/exclusions
1469 if (@tests_to_include) {
1471 for my $test (@tests_to_include) {
1472 if ($msg =~ /$test/ or ($use_valgrind
1473 and $msg =~ /valgrind\soutput/)) {
1478 return 0 unless $found;
1480 if (@tests_to_exclude) {
1482 for my $test (@tests_to_exclude) {
1483 if ($msg =~ /$test/) {
1493 sub diff_test_results() {
1495 $diff_dir1 = "${output_dir}.last" unless $diff_dir2;
1496 $diff_dir2 = $output_dir unless $diff_dir1;
1498 die "[*] Need results from a previous run before running --diff"
1499 unless -d $diff_dir2;
1500 die "[*] Current results set does not exist." unless -d $diff_dir1;
1502 my %current_tests = ();
1503 my %previous_tests = ();
1505 ### Only diff results for matching tests (parse the logfile to see which
1506 ### test numbers match across the two test cycles).
1507 &build_results_hash(\%current_tests, $diff_dir1);
1508 &build_results_hash(\%previous_tests, $diff_dir2);
1510 for my $test_msg (sort {$current_tests{$a}{'num'} <=> $current_tests{$b}{'num'}}
1511 keys %current_tests) {
1512 my $current_result = $current_tests{$test_msg}{'pass_fail'};
1513 my $current_num = $current_tests{$test_msg}{'num'};
1514 if (defined $previous_tests{$test_msg}) {
1515 print "[+] Checking: $test_msg\n";
1516 my $previous_result = $previous_tests{$test_msg}{'pass_fail'};
1517 my $previous_num = $previous_tests{$test_msg}{'num'};
1518 if ($current_result ne $previous_result) {
1519 print " DIFF: **$current_result** $test_msg\n";
1522 &diff_results($previous_num, $current_num);
1530 sub diff_results() {
1531 my ($previous_num, $current_num) = @_;
1533 ### edit out any valgrind "==354==" prefixes
1534 my $valgrind_search_re = qr/^==\d+==\s/;
1536 ### remove CMD timestamps
1537 my $cmd_search_re = qr/^\S+\s.*?\s\d{4}\sCMD\:/;
1539 for my $file ("$diff_dir1/${previous_num}.test",
1540 "$diff_dir1/${previous_num}_fwknopd.test",
1541 "$diff_dir2/${current_num}.test",
1542 "$diff_dir2/${current_num}_fwknopd.test",
1544 system qq{perl -p -i -e 's|$valgrind_search_re||' $file} if -e $file;
1545 system qq{perl -p -i -e 's|$cmd_search_re|CMD:|' $file} if -e $file;
1548 if (-e "$diff_dir1/${previous_num}.test"
1549 and -e "$diff_dir2/${current_num}.test") {
1550 system "diff -u $diff_dir1/${previous_num}.test " .
1551 "$diff_dir2/${current_num}.test";
1554 if (-e "$diff_dir1/${previous_num}_fwknopd.test"
1555 and -e "$diff_dir2/${current_num}_fwknopd.test") {
1556 system "diff -u $diff_dir1/${previous_num}_fwknopd.test " .
1557 "$diff_dir2/${current_num}_fwknopd.test";
1563 sub build_results_hash() {
1564 my ($hr, $dir) = @_;
1566 open F, "< $dir/$logfile" or die $!;
1568 if (/^(.*?)\.\.\..*(pass|fail)\s\((\d+)\)/) {
1569 $hr->{$1}{'pass_fail'} = $2;
1570 $hr->{$1}{'num'} = $3;
1576 sub compile_warnings() {
1578 ### 'make clean' as root
1579 return 0 unless &run_cmd('make -C .. clean',
1580 $cmd_out_tmp, $current_test_file);
1583 my $username = getpwuid((stat($configure_path))[4]);
1584 die "[*] Could not determine $configure_path owner"
1587 return 0 unless &run_cmd("$sudo_path -u $username make -C ..",
1588 $cmd_out_tmp, $current_test_file);
1592 return 0 unless &run_cmd('make -C ..',
1593 $cmd_out_tmp, $current_test_file);
1597 ### look for compilation warnings - something like:
1598 ### warning: ‘test’ is used uninitialized in this function
1599 return 0 if &file_find_regex([qr/\swarning:\s/, qr/gcc\:.*\sunused/],
1600 $current_test_file);
1602 ### the new binaries should exist
1603 unless (-e $fwknopCmd and -x $fwknopCmd) {
1604 &write_test_file("[-] $fwknopCmd does not exist or not executable.\n",
1605 $current_test_file);
1607 unless (-e $fwknopdCmd and -x $fwknopdCmd) {
1608 &write_test_file("[-] $fwknopdCmd does not exist or not executable.\n",
1609 $current_test_file);
1615 sub profile_coverage() {
1617 ### check for any *.gcno files - if they don't exist, then fwknop was
1618 ### not compiled with profile support
1619 unless (glob('../client/*.gcno') and glob('../server/*.gcno')) {
1620 &write_test_file("[-] ../client/*.gcno and " .
1621 "../server/*.gcno files do not exist.\n", $current_test_file);
1625 my $curr_dir = getcwd() or die $!;
1627 ### gcov -b ../client/*.gcno
1628 for my $dir ('../client', '../server', '../lib/.libs') {
1629 next unless -d $dir;
1630 chdir $dir or die $!;
1631 system "$gcov_path -b -u *.gcno > /dev/null 2>&1";
1632 chdir $curr_dir or die $!;
1634 &run_cmd(qq|grep "called 0 returned" $dir/*.gcov|,
1635 $cmd_out_tmp, $current_test_file);
1641 sub binary_exists() {
1642 my $test_hr = shift;
1643 return 0 unless $test_hr->{'binary'};
1645 ### account for different libfko.so paths (e.g. libfko.so.0.3 with no
1646 ### libfko.so link on OpenBSD)
1648 if ($test_hr->{'binary'} =~ /libfko/) {
1649 unless (-e $test_hr->{'binary'}) {
1650 for my $file (glob("$lib_dir/libfko.so*")) {
1651 if (-e $file and -x $file) {
1652 $test_hr->{'binary'} = $file;
1653 $libfko_bin = $file;
1660 return 0 unless -e $test_hr->{'binary'} and -x $test_hr->{'binary'};
1664 sub expected_code_version() {
1665 my $test_hr = shift;
1667 unless (-e '../VERSION') {
1668 &write_test_file("[-] ../VERSION file does not exist.\n",
1669 $current_test_file);
1673 open F, '< ../VERSION' or die $!;
1676 if ($line =~ /(\d.*\d)/) {
1678 return 0 unless &run_cmd($test_hr->{'cmdline'},
1679 $cmd_out_tmp, $current_test_file);
1680 return 1 if &file_find_regex([qr/$version/], $current_test_file);
1685 sub client_send_spa_packet() {
1686 my $test_hr = shift;
1688 &write_key('fwknoptest', $local_key_file);
1690 return 0 unless &run_cmd($test_hr->{'cmdline'},
1691 $cmd_out_tmp, $current_test_file);
1692 return 0 unless &file_find_regex([qr/final\spacked/i],
1693 $current_test_file);
1699 my $test_hr = shift;
1701 my ($rv, $server_was_stopped, $fw_rule_created, $fw_rule_removed)
1702 = &client_server_interaction($test_hr, [], $USE_CLIENT);
1704 if ($test_hr->{'fw_rule_created'} eq $NEW_RULE_REQUIRED) {
1705 $rv = 0 unless $fw_rule_created;
1706 } elsif ($test_hr->{'fw_rule_created'} eq $REQUIRE_NO_NEW_RULE) {
1707 $rv = 0 if $fw_rule_created;
1710 if ($test_hr->{'fw_rule_removed'} eq $NEW_RULE_REMOVED) {
1711 $rv = 0 unless $fw_rule_removed;
1712 } elsif ($test_hr->{'fw_rule_removed'} eq $REQUIRE_NO_NEW_REMOVED) {
1713 $rv = 0 if $fw_rule_removed;
1716 if ($test_hr->{'server_positive_output_matches'}) {
1717 $rv = 0 unless &file_find_regex(
1718 $test_hr->{'server_positive_output_matches'},
1722 if ($test_hr->{'server_negative_output_matches'}) {
1723 $rv = 0 if &file_find_regex(
1724 $test_hr->{'server_negative_output_matches'},
1731 sub spoof_username() {
1732 my $test_hr = shift;
1734 my $rv = &spa_cycle($test_hr);
1736 unless (&file_find_regex([qr/Username:\s*$spoof_user/],
1737 $current_test_file)) {
1741 unless (&file_find_regex([qr/Username:\s*$spoof_user/],
1742 $server_test_file)) {
1749 sub replay_detection() {
1750 my $test_hr = shift;
1752 ### do a complete SPA cycle and then parse the SPA packet out of the
1753 ### current test file and re-send
1755 return 0 unless &spa_cycle($test_hr);
1757 my $spa_pkt = &get_spa_packet_from_file($current_test_file);
1760 &write_test_file("[-] could not get SPA packet " .
1761 "from file: $current_test_file\n",
1762 $current_test_file);
1769 'port' => $default_spa_port,
1770 'dst_ip' => $loopback_ip,
1775 my ($rv, $server_was_stopped, $fw_rule_created, $fw_rule_removed)
1776 = &client_server_interaction($test_hr, \@packets, $USE_PREDEF_PKTS);
1778 $rv = 0 unless $server_was_stopped;
1780 unless (&file_find_regex([qr/Replay\sdetected\sfrom\ssource\sIP/i],
1781 $server_test_file)) {
1788 sub digest_cache_structure() {
1789 my $test_hr = shift;
1792 &run_cmd("file $default_digest_file", $cmd_out_tmp, $current_test_file);
1794 if (&file_find_regex([qr/ASCII/i], $cmd_out_tmp)) {
1796 ### the format should be:
1797 ### <digest> <proto> <src_ip> <src_port> <dst_ip> <dst_port> <time>
1798 open F, "< $default_digest_file" or
1799 die "[*] could not open $default_digest_file: $!";
1803 unless (m|^\S+\s+\d+\s+$ip_re\s+\d+\s+$ip_re\s+\d+\s+\d+|) {
1804 &write_test_file("[-] invalid digest.cache line: $_",
1805 $current_test_file);
1811 } elsif (&file_find_regex([qr/dbm/i], $cmd_out_tmp)) {
1812 &write_test_file("[+] DBM digest file format, " .
1813 "assuming this is valid.\n", $current_test_file);
1815 ### don't know what kind of file the digest.cache is
1816 &write_test_file("[-] unrecognized file type for " .
1817 "$default_digest_file.\n", $current_test_file);
1822 &write_test_file("[+] valid digest.cache structure.\n",
1823 $current_test_file);
1829 sub server_bpf_ignore_packet() {
1830 my $test_hr = shift;
1833 my $server_was_stopped = 0;
1834 my $fw_rule_created = 0;
1835 my $fw_rule_removed = 0;
1837 unless (&client_send_spa_packet($test_hr)) {
1838 &write_test_file("[-] fwknop client execution error.\n",
1839 $current_test_file);
1843 my $spa_pkt = &get_spa_packet_from_file($current_test_file);
1846 &write_test_file("[-] could not get SPA packet " .
1847 "from file: $current_test_file\n", $current_test_file);
1854 'port' => $default_spa_port,
1855 'dst_ip' => $loopback_ip,
1860 ($rv, $server_was_stopped, $fw_rule_created, $fw_rule_removed)
1861 = &client_server_interaction($test_hr, \@packets, $USE_PREDEF_PKTS);
1863 unless (&file_find_regex([qr/PCAP\sfilter.*\s$non_std_spa_port/],
1864 $server_test_file)) {
1871 sub altered_non_base64_spa_data() {
1872 my $test_hr = shift;
1875 my $server_was_stopped = 0;
1876 my $fw_rule_created = 0;
1877 my $fw_rule_removed = 0;
1879 unless (&client_send_spa_packet($test_hr)) {
1880 &write_test_file("[-] fwknop client execution error.\n",
1881 $current_test_file);
1885 my $spa_pkt = &get_spa_packet_from_file($current_test_file);
1888 &write_test_file("[-] could not get SPA packet " .
1889 "from file: $current_test_file\n", $current_test_file);
1893 ### alter one byte (change to a ":")
1894 $spa_pkt =~ s|^(.{3}).|$1:|;
1899 'port' => $default_spa_port,
1900 'dst_ip' => $loopback_ip,
1905 ($rv, $server_was_stopped, $fw_rule_created, $fw_rule_removed)
1906 = &client_server_interaction($test_hr, \@packets, $USE_PREDEF_PKTS);
1908 $rv = 0 unless $server_was_stopped;
1913 sub altered_base64_spa_data() {
1914 my $test_hr = shift;
1917 my $server_was_stopped = 0;
1918 my $fw_rule_created = 0;
1919 my $fw_rule_removed = 0;
1921 unless (&client_send_spa_packet($test_hr)) {
1922 &write_test_file("[-] fwknop client execution error.\n",
1923 $current_test_file);
1927 my $spa_pkt = &get_spa_packet_from_file($current_test_file);
1930 &write_test_file("[-] could not get SPA packet " .
1931 "from file: $current_test_file\n", $current_test_file);
1935 $spa_pkt =~ s|^(.{3}).|AAAA|;
1940 'port' => $default_spa_port,
1941 'dst_ip' => $loopback_ip,
1946 ($rv, $server_was_stopped, $fw_rule_created, $fw_rule_removed)
1947 = &client_server_interaction($test_hr, \@packets, $USE_PREDEF_PKTS);
1949 $rv = 0 unless $server_was_stopped;
1951 if ($fw_rule_created) {
1952 &write_test_file("[-] new fw rule created.\n", $current_test_file);
1955 &write_test_file("[+] new fw rule not created.\n", $current_test_file);
1958 unless (&file_find_regex([qr/Error\screating\sfko\scontext/],
1959 $server_test_file)) {
1966 sub appended_spa_data() {
1967 my $test_hr = shift;
1970 my $server_was_stopped = 0;
1971 my $fw_rule_created = 0;
1972 my $fw_rule_removed = 0;
1974 unless (&client_send_spa_packet($test_hr)) {
1975 &write_test_file("[-] fwknop client execution error.\n",
1976 $current_test_file);
1980 my $spa_pkt = &get_spa_packet_from_file($current_test_file);
1983 &write_test_file("[-] could not get SPA packet " .
1984 "from file: $current_test_file\n", $current_test_file);
1993 'port' => $default_spa_port,
1994 'dst_ip' => $loopback_ip,
1999 ($rv, $server_was_stopped, $fw_rule_created, $fw_rule_removed)
2000 = &client_server_interaction($test_hr, \@packets, $USE_PREDEF_PKTS);
2002 $rv = 0 unless $server_was_stopped;
2004 if ($fw_rule_created) {
2005 &write_test_file("[-] new fw rule created.\n", $current_test_file);
2008 &write_test_file("[+] new fw rule not created.\n", $current_test_file);
2011 unless (&file_find_regex([qr/Error\screating\sfko\scontext/],
2012 $server_test_file)) {
2019 sub prepended_spa_data() {
2020 my $test_hr = shift;
2023 my $server_was_stopped = 0;
2024 my $fw_rule_created = 0;
2025 my $fw_rule_removed = 0;
2027 unless (&client_send_spa_packet($test_hr)) {
2028 &write_test_file("[-] fwknop client execution error.\n",
2029 $current_test_file);
2033 my $spa_pkt = &get_spa_packet_from_file($current_test_file);
2036 &write_test_file("[-] could not get SPA packet " .
2037 "from file: $current_test_file\n", $current_test_file);
2041 $spa_pkt = 'AAAA' . $spa_pkt;
2046 'port' => $default_spa_port,
2047 'dst_ip' => $loopback_ip,
2052 ($rv, $server_was_stopped, $fw_rule_created, $fw_rule_removed)
2053 = &client_server_interaction($test_hr, \@packets, $USE_PREDEF_PKTS);
2055 $rv = 0 unless $server_was_stopped;
2057 if ($fw_rule_created) {
2058 &write_test_file("[-] new fw rule created.\n", $current_test_file);
2061 &write_test_file("[+] new fw rule not created.\n", $current_test_file);
2064 unless (&file_find_regex([qr/Error\screating\sfko\scontext/],
2065 $server_test_file)) {
2072 sub server_start() {
2073 my $test_hr = shift;
2075 my ($rv, $server_was_stopped, $fw_rule_created, $fw_rule_removed)
2076 = &client_server_interaction($test_hr, [], $USE_PREDEF_PKTS);
2078 unless (&file_find_regex([qr/Starting\sfwknopd\smain\sevent\sloop/],
2079 $server_test_file)) {
2083 $rv = 0 unless $server_was_stopped;
2089 my $test_hr = shift;
2091 my ($rv, $server_was_stopped, $fw_rule_created, $fw_rule_removed)
2092 = &client_server_interaction($test_hr, [], $USE_PREDEF_PKTS);
2094 $rv = 0 unless $server_was_stopped;
2099 sub server_packet_limit() {
2100 my $test_hr = shift;
2105 'port' => $default_spa_port,
2106 'dst_ip' => $loopback_ip,
2111 my ($rv, $server_was_stopped, $fw_rule_created, $fw_rule_removed)
2112 = &client_server_interaction($test_hr, \@packets, $USE_PREDEF_PKTS);
2114 if (&is_fwknopd_running()) {
2119 unless (&file_find_regex([qr/count\slimit\sof\s1\sreached/],
2120 $server_test_file)) {
2124 unless (&file_find_regex([qr/Shutting\sDown\sfwknopd/i],
2125 $server_test_file)) {
2132 sub server_ignore_small_packets() {
2133 my $test_hr = shift;
2138 'port' => $default_spa_port,
2139 'dst_ip' => $loopback_ip,
2140 'data' => 'A'x120, ### < MIN_SPA_DATA_SIZE
2144 my ($rv, $server_was_stopped, $fw_rule_created, $fw_rule_removed)
2145 = &client_server_interaction($test_hr, \@packets, $USE_PREDEF_PKTS);
2149 if (&is_fwknopd_running()) {
2157 sub client_server_interaction() {
2158 my ($test_hr, $pkts_hr, $spa_client_flag, $fw_rules_flag) = @_;
2161 my $server_was_stopped = 1;
2162 my $fw_rule_created = 1;
2163 my $fw_rule_removed = 0;
2165 ### start fwknopd to monitor for the SPA packet over the loopback interface
2166 my $fwknopd_parent_pid = &start_fwknopd($test_hr);
2168 ### give fwknopd a chance to parse its config and start sniffing
2169 ### on the loopback interface
2170 if ($use_valgrind) {
2176 ### send the SPA packet(s) to the server either manually using IO::Socket or
2177 ### with the fwknopd client
2178 if ($spa_client_flag == $USE_CLIENT) {
2179 unless (&client_send_spa_packet($test_hr)) {
2180 &write_test_file("[-] fwknop client execution error.\n",
2181 $current_test_file);
2185 &send_packets($pkts_hr);
2188 ### check to see if the SPA packet resulted in a new fw access rule
2190 while (not &is_fw_rule_active($test_hr)) {
2191 &write_test_file("[-] new fw rule does not exist.\n",
2192 $current_test_file);
2198 $fw_rule_created = 0;
2199 $fw_rule_removed = 0;
2202 &time_for_valgrind() if $use_valgrind;
2204 if ($fw_rule_created) {
2205 sleep 3; ### allow time for rule time out.
2206 if (&is_fw_rule_active($test_hr)) {
2207 &write_test_file("[-] new fw rule not timed out.\n",
2208 $current_test_file);
2211 &write_test_file("[+] new fw rule timed out.\n",
2212 $current_test_file);
2213 $fw_rule_removed = 1;
2217 if (&is_fwknopd_running()) {
2219 unless (&file_find_regex([qr/Got\sSIGTERM/, qr/^Terminated/],
2220 $server_test_file)) {
2221 $server_was_stopped = 0;
2224 &write_test_file("[-] server is not running.\n",
2225 $current_test_file);
2226 $server_was_stopped = 0;
2229 return ($rv, $server_was_stopped, $fw_rule_created, $fw_rule_removed);
2232 sub get_spa_packet_from_file() {
2237 my $found_trigger_line = 0;
2238 open F, "< $file" or die "[*] Could not open file $file: $!";
2240 if (/final\spacked/i) {
2241 $found_trigger_line = 1;
2244 next unless $found_trigger_line;
2246 ### the next line with non whitespace is the SPA packet
2257 sub send_packets() {
2258 my $pkts_ar = shift;
2260 open F, ">> $current_test_file" or die $!;
2261 print F "[+] send_packets(): Sending the following packets...\n";
2262 print F Dumper $pkts_ar;
2265 for my $pkt_hr (@$pkts_ar) {
2266 if ($pkt_hr->{'proto'} eq 'tcp' or $pkt_hr->{'proto'} eq 'udp') {
2267 my $socket = IO::Socket::INET->new(
2268 PeerAddr => $pkt_hr->{'dst_ip'},
2269 PeerPort => $pkt_hr->{'port'},
2270 Proto => $pkt_hr->{'proto'},
2272 ) or die "[*] Could not acquire $pkt_hr->{'proto'}/$pkt_hr->{'port'} " .
2273 "socket to $pkt_hr->{'dst_ip'}: $!";
2275 $socket->send($pkt_hr->{'data'});
2278 } elsif ($pkt_hr->{'proto'} eq 'http') {
2280 } elsif ($pkt_hr->{'proto'} eq 'icmp') {
2284 sleep $pkt_hr->{'delay'} if defined $pkt_hr->{'delay'};
2289 sub generic_exec() {
2290 my $test_hr = shift;
2294 my $exec_rv = &run_cmd($test_hr->{'cmdline'},
2295 $cmd_out_tmp, $current_test_file);
2297 if ($test_hr->{'exec_err'} eq $YES) {
2298 $rv = 0 if $exec_rv;
2300 $rv = 0 unless $exec_rv;
2303 if ($test_hr->{'positive_output_matches'}) {
2304 $rv = 0 unless &file_find_regex(
2305 $test_hr->{'positive_output_matches'},
2306 $current_test_file);
2309 if ($test_hr->{'negative_output_matches'}) {
2310 $rv = 0 if &file_find_regex(
2311 $test_hr->{'negative_output_matches'},
2312 $current_test_file);
2320 my $test_hr = shift;
2321 return 0 unless $test_hr->{'binary'};
2322 &run_cmd("./hardening-check $test_hr->{'binary'}",
2323 $cmd_out_tmp, $current_test_file);
2324 return 0 if &file_find_regex([qr/Position\sIndependent.*:\sno/i],
2325 $current_test_file);
2329 ### check for stack protection
2330 sub stack_protected_binary() {
2331 my $test_hr = shift;
2332 return 0 unless $test_hr->{'binary'};
2333 &run_cmd("./hardening-check $test_hr->{'binary'}",
2334 $cmd_out_tmp, $current_test_file);
2335 return 0 if &file_find_regex([qr/Stack\sprotected.*:\sno/i],
2336 $current_test_file);
2340 ### check for fortified source functions
2341 sub fortify_source_functions() {
2342 my $test_hr = shift;
2343 return 0 unless $test_hr->{'binary'};
2344 &run_cmd("./hardening-check $test_hr->{'binary'}",
2345 $cmd_out_tmp, $current_test_file);
2346 return 0 if &file_find_regex([qr/Fortify\sSource\sfunctions:\sno/i],
2347 $current_test_file);
2351 ### check for read-only relocations
2352 sub read_only_relocations() {
2353 my $test_hr = shift;
2354 return 0 unless $test_hr->{'binary'};
2355 &run_cmd("./hardening-check $test_hr->{'binary'}",
2356 $cmd_out_tmp, $current_test_file);
2357 return 0 if &file_find_regex([qr/Read.only\srelocations:\sno/i],
2358 $current_test_file);
2362 ### check for immediate binding
2363 sub immediate_binding() {
2364 my $test_hr = shift;
2365 return 0 unless $test_hr->{'binary'};
2366 &run_cmd("./hardening-check $test_hr->{'binary'}",
2367 $cmd_out_tmp, $current_test_file);
2368 return 0 if &file_find_regex([qr/Immediate\sbinding:\sno/i],
2369 $current_test_file);
2375 &run_cmd("LD_LIBRARY_PATH=$lib_dir $valgrind_str $fwknopdCmd " .
2376 "$default_server_conf_args --fw-list-all",
2377 $cmd_out_tmp, $current_test_file);
2385 'ls -l /etc', 'if [ -e /etc/issue ]; then cat /etc/issue; fi',
2386 'if [ `which iptables` ]; then iptables -V; fi',
2387 'if [ -e /proc/cpuinfo ]; then cat /proc/cpuinfo; fi',
2388 'if [ -e /proc/config.gz ]; then zcat /proc/config.gz; fi',
2389 'if [ `which gpg` ]; then gpg --version; fi',
2390 'if [ `which tcpdump` ]; then ldd `which tcpdump`; fi',
2394 'ls -l /usr/lib/*pcap*',
2395 'ls -l /usr/local/lib/*pcap*',
2396 'ls -l /usr/lib/*fko*',
2397 'ls -l /usr/local/lib/*fko*',
2399 &run_cmd($cmd, $cmd_out_tmp, $current_test_file);
2401 if ($cmd =~ /^ldd/) {
2402 $have_gpgme++ if &file_find_regex([qr/gpgme/], $cmd_out_tmp);
2406 ### all three of fwknop/fwknopd/libfko must link against gpgme in order
2407 ### to enable gpg tests
2408 unless ($have_gpgme == 3) {
2409 push @tests_to_exclude, "GPG";
2415 sub time_for_valgrind() {
2417 while (&run_cmd("ps axuww | grep LD_LIBRARY_PATH | " .
2418 "grep valgrind |grep -v perl | grep -v grep",
2419 $cmd_out_tmp, $current_test_file)) {
2427 sub anonymize_results() {
2429 die "[*] $output_dir does not exist" unless -d $output_dir;
2430 die "[*] $logfile does not exist, has $0 been executed?"
2433 unlink $tarfile or die "[*] Could not unlink $tarfile: $!";
2436 ### remove non-loopback IP addresses
2437 my $search_re = qr/\b127\.0\.0\.1\b/;
2438 system "perl -p -i -e 's|$search_re|00MY1271STR00|g' $output_dir/*.test";
2439 $search_re = qr/\b127\.0\.0\.2\b/;
2440 system "perl -p -i -e 's|$search_re|00MY1272STR00|g' $output_dir/*.test";
2441 $search_re = qr/\b0\.0\.0\.0\b/;
2442 system "perl -p -i -e 's|$search_re|00MY0000STR00|g' $output_dir/*.test";
2443 $search_re = qr/\b(?:[0-2]?\d{1,2}\.){3}[0-2]?\d{1,2}\b/;
2444 system "perl -p -i -e 's|$search_re|N.N.N.N|g' $output_dir/*.test";
2445 system "perl -p -i -e 's|00MY1271STR00|127.0.0.1|g' $output_dir/*.test";
2446 system "perl -p -i -e 's|00MY1272STR00|127.0.0.2|g' $output_dir/*.test";
2447 system "perl -p -i -e 's|00MY0000STR00|0.0.0.0|g' $output_dir/*.test";
2449 ### remove hostname from any uname output
2450 $search_re = qr/\suname\s+\-a\s*\n\s*(\S+)\s+\S+/;
2451 system "perl -p -i -e 'undef \$/; s|$search_re" .
2452 "| uname -a\n\$1 (removed)|s' $output_dir/*.test";
2454 $search_re = qr/uname=\x27(\S+)\s+\S+/;
2455 system "perl -p -i -e 's|$search_re|uname= \$1 (removed)|' $output_dir/*.test";
2458 system "tar cvfz $tarfile $logfile $output_dir";
2459 print "[+] Anonymized test results file: $tarfile\n";
2468 my $test_hr = shift;
2470 open F, "> $default_pid_file" or die $!;
2474 &server_start($test_hr);
2476 open F, "< $default_pid_file" or die $!;
2488 sub start_fwknopd() {
2489 my $test_hr = shift;
2491 &write_test_file("[+] TEST: $test_hr->{'msg'}\n", $server_test_file);
2494 die "[*] Could not fork: $!" unless defined $pid;
2498 ### we are the child, so start fwknopd
2499 exit &run_cmd($test_hr->{'fwknopd_cmdline'},
2500 $server_cmd_tmp, $server_test_file);
2506 my ($key, $file) = @_;
2508 open K, "> $file" or die "[*] Could not open $file: $!";
2509 print K "$loopback_ip: $key\n";
2510 print K "localhost: $key\n";
2511 print K "some.host.through.proxy.com: $key\n";
2517 open C, ">> $current_test_file"
2518 or die "[*] Could not open $current_test_file: $!";
2519 print C "\n" . localtime() . " [+] PID dump:\n";
2521 &run_cmd("ps auxww | grep knop |grep -v grep",
2522 $cmd_out_tmp, $current_test_file);
2527 my ($cmd, $cmd_out, $file) = @_;
2531 or die "[*] Could not open $file: $!";
2532 print F localtime() . " CMD: $cmd\n";
2536 or die "[*] Could not open $file: $!";
2537 print F localtime() . " CMD: $cmd\n";
2541 my $rv = ((system "$cmd > $cmd_out 2>&1") >> 8);
2543 open C, "< $cmd_out" or die "[*] Could not open $cmd_out: $!";
2544 my @cmd_lines = <C>;
2547 open F, ">> $file" or die "[*] Could not open $file: $!";
2548 print F $_ for @cmd_lines;
2561 for (my $i=length($msg); $i < $PRINT_LEN; $i++) {
2570 $|++; ### turn off buffering
2572 $< == 0 && $> == 0 or
2573 die "[*] $0: You must be root (or equivalent ",
2574 "UID 0 account) to effectively test fwknop";
2576 ### validate test hashes
2578 for my $test_hr (@tests) {
2579 for my $key (keys %test_keys) {
2580 if ($test_keys{$key} == $REQUIRED) {
2581 die "[*] Missing '$key' element in hash: $hash_num"
2582 unless defined $test_hr->{$key};
2584 $test_hr->{$key} = '' unless defined $test_hr->{$key};
2590 if ($use_valgrind) {
2591 die "[*] $valgrindCmd exec problem, use --valgrind-path"
2592 unless -e $valgrindCmd and -x $valgrindCmd;
2595 die "[*] $conf_dir directory does not exist." unless -d $conf_dir;
2596 die "[*] $lib_dir directory does not exist." unless -d $lib_dir;
2598 for my $file ($configure_path,
2601 $default_access_conf,
2602 $no_source_match_access_conf,
2603 $ip_source_match_access_conf,
2604 $subnet_source_match_access_conf,
2605 $no_subnet_source_match_access_conf,
2606 $no_multi_source_match_access_conf,
2607 $multi_source_match_access_conf,
2608 $open_ports_access_conf,
2609 $mismatch_open_ports_access_conf,
2610 $require_user_access_conf,
2611 $mismatch_user_access_conf,
2612 $require_src_access_conf,
2613 $multi_gpg_access_conf,
2614 $multi_stanzas_access_conf,
2615 $expired_access_conf,
2616 $expired_epoch_access_conf,
2617 $future_expired_access_conf,
2618 $invalid_expire_access_conf,
2619 $force_nat_access_conf,
2621 die "[*] $file does not exist" unless -e $file;
2624 if (-d $output_dir) {
2625 if (-d "${output_dir}.last") {
2626 rmtree "${output_dir}.last"
2627 or die "[*] rmtree ${output_dir}.last $!";
2629 mkdir "${output_dir}.last"
2630 or die "[*] ${output_dir}.last: $!";
2631 for my $file (glob("$output_dir/*.test")) {
2632 if ($file =~ m|.*/(.*)|) {
2633 copy $file, "${output_dir}.last/$1" or die $!;
2636 if (-e "$output_dir/init") {
2637 copy "$output_dir/init", "${output_dir}.last/init";
2640 copy $logfile, "${output_dir}.last/$logfile" or die $!;
2642 $saved_last_results = 1;
2644 mkdir $output_dir or die "[*] Could not mkdir $output_dir: $!";
2646 unless (-d $run_dir) {
2647 mkdir $run_dir or die "[*] Could not mkdir $run_dir: $!";
2650 for my $file (glob("$output_dir/*.test")) {
2651 unlink $file or die "[*] Could not unlink($file)";
2653 if (-e "$output_dir/init") {
2654 unlink "$output_dir/init" or die $!;
2658 unlink $logfile or die $!;
2661 if ($test_include) {
2662 @tests_to_include = split /\s*,\s*/, $test_include;
2664 if ($test_exclude) {
2665 @tests_to_exclude = split /\s*,\s*/, $test_exclude;
2668 ### make sure no fwknopd instance is currently running
2669 die "[*] Please stop the running fwknopd instance."
2670 if &is_fwknopd_running();
2672 unless ($enable_recompilation_warnings_check) {
2673 push @tests_to_exclude, 'recompilation';
2676 unless ($enable_profile_coverage_check) {
2677 push @tests_to_exclude, 'profile coverage';
2680 $sudo_path = &find_command('sudo');
2682 unless ((&find_command('cc') or &find_command('gcc')) and &find_command('make')) {
2683 ### disable compilation checks
2684 push @tests_to_exclude, 'recompilation';
2687 $gcov_path = &find_command('gcov');
2690 if ($enable_profile_coverage_check) {
2691 for my $extension ('*.gcov', '*.gcda') {
2692 ### remove profile output from any previous run
2693 system qq{find .. -name $extension | xargs rm 2> /dev/null};
2697 push @tests_to_exclude, 'profile coverage';
2700 open UNAME, "uname |" or die "[*] Could not execute uname: $!";
2703 $platform = 'linux';
2709 unless ($platform eq 'linux') {
2710 push @tests_to_exclude, 'NAT';
2716 sub identify_loopback_intf() {
2717 return if $loopback_intf;
2721 ### lo Link encap:Local Loopback
2722 ### inet addr:127.0.0.1 Mask:255.0.0.0
2723 ### inet6 addr: ::1/128 Scope:Host
2724 ### UP LOOPBACK RUNNING MTU:16436 Metric:1
2725 ### RX packets:534709 errors:0 dropped:0 overruns:0 frame:0
2726 ### TX packets:534709 errors:0 dropped:0 overruns:0 carrier:0
2727 ### collisions:0 txqueuelen:0
2728 ### RX bytes:101110617 (101.1 MB) TX bytes:101110617 (101.1 MB)
2732 ### lo0: flags=8049<UP,LOOPBACK,RUNNING,MULTICAST> metric 0 mtu 16384
2733 ### options=3<RXCSUM,TXCSUM>
2734 ### inet6 fe80::1%lo0 prefixlen 64 scopeid 0x2
2735 ### inet6 ::1 prefixlen 128
2736 ### inet 127.0.0.1 netmask 0xff000000
2737 ### nd6 options=3<PERFORMNUD,ACCEPT_RTADV>
2740 my $found_loopback_intf = 0;
2742 my $cmd = 'ifconfig -a';
2743 open C, "$cmd |" or die "[*] (use --loopback <name>) $cmd: $!";
2745 if (/^(\S+?):?\s+.*loopback/i) {
2749 if (/^\S/ and $intf and not $found_loopback_intf) {
2750 ### should not happen
2753 if ($intf and /\b127\.0\.0\.1\b/) {
2754 $found_loopback_intf = 1;
2760 die "[*] could not determine loopback interface, use --loopback <name>"
2761 unless $found_loopback_intf;
2763 $loopback_intf = $intf;
2768 sub parse_valgrind_flagged_functions() {
2769 for my $file (glob("$output_dir/*.test")) {
2770 my $type = 'server';
2771 $type = 'client' if $file =~ /\d\.test/;
2772 open F, "< $file" or die $!;
2774 ### ==30969== by 0x4E3983A: fko_set_username (fko_user.c:65)
2775 if (/^==.*\sby\s\S+\:\s(\S+)\s(.*)/) {
2776 $valgrind_flagged_fcns{$type}{"$1 $2"}++;
2777 $valgrind_flagged_fcns_unique{$type}{$1}++;
2783 open F, ">> $current_test_file" or die $!;
2784 for my $type ('client', 'server') {
2785 print F "\n[+] fwknop $type functions (unique view):\n";
2786 next unless defined $valgrind_flagged_fcns_unique{$type};
2787 for my $fcn (sort {$valgrind_flagged_fcns_unique{$type}{$b}
2788 <=> $valgrind_flagged_fcns_unique{$type}{$a}}
2789 keys %{$valgrind_flagged_fcns_unique{$type}}) {
2790 printf F " %5d : %s\n", $valgrind_flagged_fcns_unique{$type}{$fcn}, $fcn;
2792 print F "\n[+] fwknop $type functions (with call line numbers):\n";
2793 for my $fcn (sort {$valgrind_flagged_fcns{$type}{$b}
2794 <=> $valgrind_flagged_fcns{$type}{$a}} keys %{$valgrind_flagged_fcns{$type}}) {
2795 printf F " %5d : %s\n", $valgrind_flagged_fcns{$type}{$fcn}, $fcn;
2797 next unless defined $valgrind_flagged_fcns{$type};
2804 sub is_fw_rule_active() {
2805 my $test_hr = shift;
2807 my $conf_args = $default_server_conf_args;
2809 if ($test_hr->{'server_conf'}) {
2810 $conf_args = "-c $test_hr->{'server_conf'} -a $default_access_conf " .
2811 "-d $default_digest_file -p $default_pid_file";
2814 return 1 if &run_cmd("LD_LIBRARY_PATH=$lib_dir $fwknopdCmd " .
2815 qq{$conf_args --fw-list | grep -v "# DISABLED" |grep $fake_ip |grep _exp_},
2816 $cmd_out_tmp, $current_test_file);
2820 sub is_fwknopd_running() {
2822 sleep 2 if $use_valgrind;
2824 &run_cmd("LD_LIBRARY_PATH=$lib_dir $fwknopdCmd $default_server_conf_args " .
2825 "--status", $cmd_out_tmp, $current_test_file);
2827 return 0 if &file_find_regex([qr/no\s+running/i], $cmd_out_tmp);
2832 sub stop_fwknopd() {
2834 &run_cmd("LD_LIBRARY_PATH=$lib_dir $fwknopdCmd " .
2835 "$default_server_conf_args -K", $cmd_out_tmp, $current_test_file);
2837 if ($use_valgrind) {
2838 &time_for_valgrind();
2846 sub file_find_regex() {
2847 my ($re_ar, $file) = @_;
2850 my @write_lines = ();
2852 open F, "< $file" or die "[*] Could not open $file: $!";
2855 next LINE if $line =~ /file_file_regex\(\)/;
2856 for my $re (@$re_ar) {
2858 push @write_lines, "[.] file_find_regex() " .
2859 "Matched '$re' with line: $line";
2868 for my $line (@write_lines) {
2869 &write_test_file($line, $file);
2872 &write_test_file("[.] find_find_regex() Did not " .
2873 "match any regex in: '@$re_ar'\n", $file);
2879 sub find_command() {
2883 open C, "which $cmd |" or die "[*] Could not execute: which $cmd: $!";
2885 if (m|^(/.*$cmd)$|) {
2894 sub write_test_file() {
2895 my ($msg, $file) = @_;
2899 or die "[*] Could not open $file: $!";
2904 or die "[*] Could not open $file: $!";
2914 open F, ">> $logfile" or die $!;
2925 -A --Anonymize-results - Prepare anonymized results at:
2927 --diff - Compare the results of one test run to
2928 another. By default this compares output
2929 in ${output_dir}.last to $output_dir
2930 --diff-dir1=<path> - Left hand side of diff directory path,
2931 default is: ${output_dir}.last
2932 --diff-dir2=<path> - Right hand side of diff directory path,
2933 default is: $output_dir
2934 --include=<regex> - Specify a regex to be used over test
2935 names that must match.
2936 --exclude=<regex> - Specify a regex to be used over test
2937 names that must not match.
2938 --enable-recompile - Recompile fwknop sources and look for
2939 compilation warnings.
2940 --enable-valgrind - Run every test underneath valgrind.
2941 --List - List test names.
2942 --loopback-intf=<intf> - Specify loopback interface name (default
2943 depends on the OS where the test suite
2945 --output-dir=<path> - Path to output directory, default is:
2947 --fwknop-path=<path> - Path to fwknop binary, default is:
2949 --fwknopd-path=<path> - Path to fwknopd binary, default is:
2951 --libfko-path=<path> - Path to libfko, default is:
2953 --valgrind-path=<path> - Path to valgrind, default is:
2955 -h --help - Display usage on STDOUT and exit.