--- /dev/null
+#!/usr/bin/perl -w
+
+use lib (qw|../lib ../../IPTables-Parse/lib ../../IPTables-Parse.git/lib|);
+use Data::Dumper;
+use strict;
+
+eval {
+ require IPTables::ChainMgr;
+};
+die "[*] Adjust 'use lib' statement to include ",
+ "directory where IPTables::Parse lives" if $@;
+
+#==================== config =====================
+my $iptables_bin = '/sbin/iptables';
+my $ip6tables_bin = '/sbin/ip6tables';
+
+my $test_table = 'filter';
+my $test_chain = 'CHAINMGR';
+my $test_jump_from_chain = 'INPUT';
+
+### normalization will produce the correct network addresses ("10.1.2.3/24" is
+### deliberate)
+my $ipv4_src = '10.1.2.3/24';
+my $ipv4_dst = '192.168.1.2';
+my $ipv6_src = 'fe80::200:f8ff:fe21:67cf';
+my $ipv6_dst = '0000:0000:00AA:0000:0000:AA00:0000:0001/64';
+
+my $logfile = 'test.log';
+my $PRINT_LEN = 68;
+my $chain_past_end = 1000;
+#================== end config ===================
+
+my %targets = (
+ 'ACCEPT' => '',
+ 'DROP' => '',
+ 'QUEUE' => '',
+ 'RETURN' => '',
+);
+
+my %iptables_chains = (
+ 'mangle' => [qw/PREROUTING INPUT OUTPUT FORWARD POSTROUTING/],
+ 'raw' => [qw/PREROUTING OUTPUT/],
+ 'filter' => [qw/INPUT OUTPUT FORWARD/],
+ 'nat' => [qw/PREROUTING OUTPUT POSTROUTING/]
+);
+
+my %ip6tables_chains = (
+ 'mangle' => [qw/PREROUTING INPUT OUTPUT FORWARD POSTROUTING/],
+ 'raw' => [qw/PREROUTING OUTPUT/],
+ 'filter' => [qw/INPUT OUTPUT FORWARD/],
+);
+
+my $passed = 0;
+my $failed = 0;
+my $executed = 0;
+
+&init();
+
+&iptables_tests();
+&ip6tables_tests();
+
+&logr("\n[+] passed/failed/executed: $passed/$failed/$executed tests\n\n");
+
+exit 0;
+
+sub iptables_tests() {
+
+ &logr("\n[+] Running $iptables_bin tests...\n");
+ my %opts = (
+ 'iptables' => $iptables_bin,
+ 'iptout' => '/tmp/iptables.out',
+ 'ipterr' => '/tmp/iptables.err',
+ 'debug' => 0,
+ 'verbose' => 0
+ );
+
+ my $ipt_obj = new IPTables::ChainMgr(%opts)
+ or die "[*] Could not acquire IPTables::ChainMgr object";
+
+ ### built-in chains
+ &chain_exists_tests($ipt_obj, \%iptables_chains);
+
+ &test_cycle($ipt_obj);
+
+ return;
+}
+
+sub ip6tables_tests() {
+
+ &logr("\n[+] Running $ip6tables_bin tests...\n");
+ my %opts = (
+ 'ip6tables' => $ip6tables_bin,
+ 'iptout' => '/tmp/ip6tables.out',
+ 'ipterr' => '/tmp/ip6tables.err',
+ 'debug' => 0,
+ 'verbose' => 0
+ );
+
+ my $ipt_obj = new IPTables::ChainMgr(%opts)
+ or die "[*] Could not acquire IPTables::ChainMgr object";
+
+ ### built-in chains
+ &chain_exists_tests($ipt_obj, \%ip6tables_chains);
+
+ &test_cycle($ipt_obj);
+
+ return;
+}
+
+sub test_cycle() {
+ my $ipt_obj = shift;
+
+ &custom_chain_init($ipt_obj, $test_table,
+ $test_jump_from_chain, $test_chain);
+
+ ### create/delete chain cycle
+ &chain_does_not_exist_test($ipt_obj, $test_table, $test_chain);
+ &create_chain_test($ipt_obj, $test_table, $test_chain);
+ &flush_chain_test($ipt_obj, $test_table, $test_chain);
+ &delete_chain_test($ipt_obj, $test_table, $test_jump_from_chain, $test_chain);
+
+ ### create chain, add rules, delete chain cycle
+ &chain_does_not_exist_test($ipt_obj, $test_table, $test_chain);
+ &create_chain_test($ipt_obj, $test_table, $test_chain);
+ &add_rules_tests($ipt_obj, $test_table, $test_chain);
+ &flush_chain_test($ipt_obj, $test_table, $test_chain);
+ &delete_chain_test($ipt_obj, $test_table, $test_jump_from_chain, $test_chain);
+
+ ### create chain add rules, add jump rule, delete chain cycle
+ &chain_does_not_exist_test($ipt_obj, $test_table, $test_chain);
+ &create_chain_test($ipt_obj, $test_table, $test_chain);
+ &add_rules_tests($ipt_obj, $test_table, $test_chain);
+ &find_rules_tests($ipt_obj, $test_table, $test_chain);
+ &add_extended_rules_tests($ipt_obj, $test_table, $test_chain);
+ &find_extended_rules_tests($ipt_obj, $test_table, $test_chain);
+ &add_jump_rule_test($ipt_obj, $test_table, $test_chain);
+ &find_jump_rule_test($ipt_obj, $test_table, $test_chain);
+ &flush_chain_test($ipt_obj, $test_table, $test_chain);
+ &set_chain_policy_test($ipt_obj, $test_table, $test_chain);
+ &delete_chain_test($ipt_obj, $test_table, $test_jump_from_chain, $test_chain);
+
+ return;
+}
+
+sub chain_exists_tests() {
+ my ($ipt_obj, $tables_chains_hr) = @_;
+
+ for my $table (keys %$tables_chains_hr) {
+ for my $chain (@{$tables_chains_hr->{$table}}) {
+ &dots_print("chain_exists(): $table $chain");
+
+ my ($rv, $out_ar, $err_ar) = $ipt_obj->chain_exists($table, $chain);
+
+ &pass_fail($rv, " $table chain $chain does not exist.");
+ }
+ }
+
+ return;
+}
+
+sub flush_chain_test() {
+ my ($ipt_obj, $test_table, $test_chain) = @_;
+
+ &dots_print("flush_chain(): $test_table $test_chain");
+
+ my ($rv, $out_ar, $err_ar) = $ipt_obj->flush_chain($test_table, $test_chain);
+ &pass_fail($rv, " Could not flush $test_table $test_chain chain.");
+
+ return;
+}
+
+sub set_chain_policy_test() {
+ my ($ipt_obj, $test_table, $test_chain) = @_;
+
+ for my $target (qw/DROP ACCEPT/) {
+ &dots_print("cannot set chain policy: $test_table $test_chain $target");
+
+ my ($rv, $out_ar, $err_ar) = $ipt_obj->set_chain_policy($test_table,
+ $test_chain, $target);
+
+ if ($rv) { ### bad, cannot set policy for a non built-in chain
+ $rv = 0;
+ } else {
+ $rv = 1;
+ }
+
+ &pass_fail($rv, " Was able to set $test_table $test_chain chain " .
+ "policy to $target, should only be able to do this for built-in chains.");
+ }
+
+ return;
+}
+
+
+sub add_jump_rule_test() {
+ my ($ipt_obj, $test_table, $test_chain) = @_;
+
+ &dots_print("add_jump_rule(): $test_table $test_jump_from_chain -> $test_chain ");
+ my ($rv, $out_ar, $err_ar) = $ipt_obj->add_jump_rule($test_table,
+ $test_jump_from_chain, 1, $test_chain);
+
+ &pass_fail($rv, " Could not add jump rule.");
+
+ return;
+}
+
+sub find_jump_rule_test() {
+ my ($ipt_obj, $test_table, $test_chain) = @_;
+
+ my $ip_any_net = '0.0.0.0/0';
+ $ip_any_net = '::/0' if $ipt_obj->{'_ipt_bin_name'} eq 'ip6tables';
+
+ &dots_print("find jump rule: $test_table $test_jump_from_chain -> $test_chain ");
+
+ my ($rule_position, $num_chain_rules) = $ipt_obj->find_ip_rule($ip_any_net,
+ $ip_any_net, $test_table, $test_jump_from_chain, $test_chain, {});
+
+ &pass_fail($rule_position, " Could not find jump rule.");
+
+ return;
+}
+
+
+sub add_rules_tests() {
+ my ($ipt_obj, $test_table, $test_chain) = @_;
+
+ my $src_ip = $ipt_obj->normalize_net($ipv4_src);
+ my $dst_ip = $ipt_obj->normalize_net($ipv4_dst);
+
+ if ($ipt_obj->{'_ipt_bin_name'} eq 'ip6tables') {
+ $src_ip = $ipt_obj->normalize_net($ipv6_src);
+ $dst_ip = $ipt_obj->normalize_net($ipv6_dst);
+ }
+
+ for my $target (qw/LOG ACCEPT RETURN/) {
+ &dots_print("add_ip_rules(): $test_table $test_chain $src_ip -> $dst_ip $target ");
+ my ($rv, $out_ar, $err_ar) = $ipt_obj->add_ip_rule($src_ip,
+ $dst_ip, $chain_past_end, $test_table, $test_chain, $target, {});
+
+ &pass_fail($rv, " Could not add $src_ip -> $dst_ip $target rule.");
+ }
+
+ return;
+}
+
+sub find_rules_tests() {
+ my ($ipt_obj, $test_table, $test_chain) = @_;
+
+ my $src_ip = $ipt_obj->normalize_net($ipv4_src);
+ my $dst_ip = $ipt_obj->normalize_net($ipv4_dst);
+
+ if ($ipt_obj->{'_ipt_bin_name'} eq 'ip6tables') {
+ $src_ip = $ipt_obj->normalize_net($ipv6_src);
+ $dst_ip = $ipt_obj->normalize_net($ipv6_dst);
+ }
+
+ for my $target (qw/LOG ACCEPT RETURN/) {
+ &dots_print("find rule: $test_table $test_chain $src_ip -> $dst_ip $target ");
+ my ($rule_position, $num_chain_rules) = $ipt_obj->find_ip_rule($src_ip,
+ $dst_ip, $test_table, $test_chain, $target, {'normalize' => 1});
+
+ &pass_fail($rule_position, " Could not find $src_ip -> $dst_ip $target rule.");
+ }
+
+ return;
+}
+
+sub add_extended_rules_tests() {
+ my ($ipt_obj, $test_table, $test_chain) = @_;
+
+ my $src_ip = $ipt_obj->normalize_net($ipv4_src);
+ my $dst_ip = $ipt_obj->normalize_net($ipv4_dst);
+
+ if ($ipt_obj->{'_ipt_bin_name'} eq 'ip6tables') {
+ $src_ip = $ipt_obj->normalize_net($ipv6_src);
+ $dst_ip = $ipt_obj->normalize_net($ipv6_dst);
+ }
+
+ for my $target (qw/LOG ACCEPT RETURN/) {
+
+ ### TCP
+ &dots_print("add_ip_rules(): $test_table $test_chain TCP $src_ip(0) -> $dst_ip(80) $target ");
+ my ($rv, $out_ar, $err_ar) = $ipt_obj->add_ip_rule($src_ip,
+ $dst_ip, $chain_past_end, $test_table, $test_chain, $target,
+ {'protocol' => 'tcp', 's_port' => 0, 'd_port' => 80});
+ &pass_fail($rv, " Could not add TCP $src_ip(0) -> $dst_ip(80) $target rule");
+
+ ### TCP + state tracking
+ &dots_print("add_ip_rules(): $test_table $test_chain TCP $src_ip(0) -> $dst_ip(80) state ESTABLISHED,RELATED $target ");
+ ($rv, $out_ar, $err_ar) = $ipt_obj->add_ip_rule($src_ip,
+ $dst_ip, $chain_past_end, $test_table, $test_chain, $target,
+ {'protocol' => 'tcp', 's_port' => 0, 'd_port' => 80, 'state' => 'ESTABLISHED,RELATED'});
+ &pass_fail($rv, " Could not add TCP $src_ip(0) -> $dst_ip(80) state ESTABLISHED,RELATED $target rule");
+
+ ### TCP + ctstate tracking
+ &dots_print("add_ip_rules(): $test_table $test_chain TCP $src_ip(0) -> $dst_ip(80) ctstate ESTABLISHED,RELATED $target ");
+ ($rv, $out_ar, $err_ar) = $ipt_obj->add_ip_rule($src_ip,
+ $dst_ip, $chain_past_end, $test_table, $test_chain, $target,
+ {'protocol' => 'tcp', 's_port' => 0, 'd_port' => 80, 'ctstate' => 'ESTABLISHED,RELATED'});
+ &pass_fail($rv, " Could not add TCP $src_ip(0) -> $dst_ip(80) ctstate ESTABLISHED,RELATED $target rule");
+
+ ### UDP
+ &dots_print("add_ip_rules(): $test_table $test_chain UDP $src_ip(0) -> $dst_ip(53) $target ");
+ ($rv, $out_ar, $err_ar) = $ipt_obj->add_ip_rule($src_ip,
+ $dst_ip, $chain_past_end, $test_table, $test_chain, $target,
+ {'protocol' => 'udp', 's_port' => 0, 'd_port' => 53});
+ &pass_fail($rv, " Could not add UDP $src_ip(0) -> $dst_ip(53) $target rule");
+
+ }
+
+ return;
+}
+
+sub find_extended_rules_tests() {
+ my ($ipt_obj, $test_table, $test_chain) = @_;
+
+ my $src_ip = $ipt_obj->normalize_net($ipv4_src);
+ my $dst_ip = $ipt_obj->normalize_net($ipv4_dst);
+
+ if ($ipt_obj->{'_ipt_bin_name'} eq 'ip6tables') {
+ $src_ip = $ipt_obj->normalize_net($ipv6_src);
+ $dst_ip = $ipt_obj->normalize_net($ipv6_dst);
+ }
+
+ for my $target (qw/LOG ACCEPT RETURN/) {
+ &dots_print("find rule: $test_table $test_chain TCP $src_ip(0) -> $dst_ip(80) $target ");
+ my ($rule_position, $num_chain_rules) = $ipt_obj->find_ip_rule($src_ip,
+ $dst_ip, $test_table, $test_chain, $target,
+ {'normalize' => 1, 'protocol' => 'tcp', 's_port' => 0, 'd_port' => 80});
+ &pass_fail($rule_position, " Could not find TCP $src_ip(0) -> $dst_ip(80) $target rule");
+
+ &dots_print("find rule: $test_table $test_chain TCP $src_ip(0) -> $dst_ip(80) state ESTABLISHED,RELATED $target ");
+ ($rule_position, $num_chain_rules) = $ipt_obj->find_ip_rule($src_ip,
+ $dst_ip, $test_table, $test_chain, $target,
+ {'normalize' => 1, 'protocol' => 'tcp', 's_port' => 0,
+ 'd_port' => 80, 'state' => 'ESTABLISHED,RELATED'});
+ &pass_fail($rule_position, " Could not find TCP $src_ip(0) -> $dst_ip(80) state ESTABLISHED,RELATED $target rule");
+
+ &dots_print("find rule: $test_table $test_chain TCP $src_ip(0) -> $dst_ip(80) ctstate ESTABLISHED,RELATED $target ");
+ ($rule_position, $num_chain_rules) = $ipt_obj->find_ip_rule($src_ip,
+ $dst_ip, $test_table, $test_chain, $target,
+ {'normalize' => 1, 'protocol' => 'tcp', 's_port' => 0,
+ 'd_port' => 80, 'ctstate' => 'ESTABLISHED,RELATED'});
+ &pass_fail($rule_position, " Could not find TCP $src_ip(0) -> $dst_ip(80) ctstate ESTABLISHED,RELATED $target rule");
+
+ &dots_print("find rule: $test_table $test_chain UDP $src_ip(0) -> $dst_ip(53) $target ");
+ ($rule_position, $num_chain_rules) = $ipt_obj->find_ip_rule($src_ip,
+ $dst_ip, $test_table, $test_chain, $target,
+ {'normalize' => 1, 'protocol' => 'udp', 's_port' => 0, 'd_port' => 53});
+ &pass_fail($rule_position, " Could not find UDP $src_ip(0) -> $dst_ip(53) $target rule");
+ }
+
+ return;
+}
+
+
+sub create_chain_test() {
+ my ($ipt_obj, $test_table, $test_chain) = @_;
+
+ &dots_print("create_chain(): $test_table $test_chain");
+
+ my ($rv, $out_ar, $err_ar) = $ipt_obj->create_chain($test_table, $test_chain);
+
+ &pass_fail($rv, " Could not create $test_table $test_chain chain");
+ die "[*] FATAL" unless $rv;
+
+ return;
+}
+
+sub chain_does_not_exist_test() {
+ my ($ipt_obj, $test_table, $test_chain) = @_;
+
+ &dots_print("!chain_exists(): $test_table $test_chain");
+
+ my ($rv, $out_ar, $err_ar) = $ipt_obj->chain_exists($test_table, $test_chain);
+
+ if ($rv) {
+ $rv = 0;
+ } else {
+ $rv = 1;
+ }
+ &pass_fail(++$rv, " Chain exists.");
+ die "[*] FATAL" unless $rv;
+
+ return;
+}
+
+sub custom_chain_init() {
+ my ($ipt_obj, $test_table, $test_jump_from_chain, $test_chain) = @_;
+
+ my ($rv, $out_ar, $err_ar) = $ipt_obj->chain_exists($test_table,
+ $test_chain);
+ if ($rv) {
+ $ipt_obj->delete_chain($test_table, $test_jump_from_chain, $test_chain);
+ }
+ return;
+}
+
+sub delete_chain_test() {
+ my ($ipt_obj, $test_table, $test_jump_from_chain, $test_chain) = @_;
+
+ &dots_print("delete_chain(): $test_table $test_chain");
+
+ my ($rv, $out_ar, $err_ar) = $ipt_obj->delete_chain($test_table,
+ $test_jump_from_chain, $test_chain);
+
+ &pass_fail($rv, " Could not delete chain.");
+ die "[*] FATAL" unless $rv;
+
+ return;
+}
+
+sub dots_print() {
+ my $msg = shift;
+ &logr($msg);
+ my $dots = '';
+ for (my $i=length($msg); $i < $PRINT_LEN; $i++) {
+ $dots .= '.';
+ }
+ &logr($dots);
+ return;
+}
+
+sub pass_fail() {
+ my ($rv, $fail_msg) = @_;
+
+ $executed++;
+
+ if ($rv) {
+ &logr("pass ($executed)\n");
+ $passed++;
+ } else {
+ &logr("fail ($executed)\n");
+ &logr("$fail_msg\n");
+ $failed++;
+ }
+
+ return;
+}
+
+sub logr() {
+ my $msg = shift;
+ print STDOUT $msg;
+ open F, ">> $logfile" or die $!;
+ print F $msg;
+ close F;
+ return;
+}
+
+sub init() {
+
+ $|++; ### turn off buffering
+
+ $< == 0 && $> == 0 or
+ die "[*] $0: You must be root (or equivalent ",
+ "UID 0 account) to effectively test fwknop";
+
+ unlink $logfile if -e $logfile;
+ for my $bin ($iptables_bin, $ip6tables_bin) {
+ die "[*] $bin does not exist" unless -e $bin;
+ die "[*] $bin not executable" unless -x $bin;
+ }
+
+ return;
+}
--- /dev/null
+#!/usr/bin/perl -w
+
+use lib '../lib';
+use Data::Dumper;
+use strict;
+
+require IPTables::Parse;
+
+#==================== config =====================
+my $iptables_bin = '/sbin/iptables';
+my $ip6tables_bin = '/sbin/ip6tables';
+
+my $logfile = 'test.log';
+my $PRINT_LEN = 68;
+#================== end config ===================
+
+my %targets = (
+ 'ACCEPT' => '',
+ 'DROP' => '',
+ 'QUEUE' => '',
+ 'RETURN' => '',
+);
+
+my %iptables_chains = (
+ 'mangle' => [qw/PREROUTING INPUT OUTPUT FORWARD POSTROUTING/],
+ 'raw' => [qw/PREROUTING OUTPUT/],
+ 'filter' => [qw/INPUT OUTPUT FORWARD/],
+ 'nat' => [qw/PREROUTING OUTPUT POSTROUTING/]
+);
+
+my %ip6tables_chains = (
+ 'mangle' => [qw/PREROUTING INPUT OUTPUT FORWARD POSTROUTING/],
+ 'raw' => [qw/PREROUTING OUTPUT/],
+ 'filter' => [qw/INPUT OUTPUT FORWARD/],
+);
+
+my $passed = 0;
+my $failed = 0;
+my $executed = 0;
+
+&init();
+
+&iptables_tests();
+&ip6tables_tests();
+
+&logr("\n[+] passed/failed/executed: $passed/$failed/$executed tests\n\n");
+
+exit 0;
+
+sub iptables_tests() {
+
+ &logr("[+] Running $iptables_bin tests...\n");
+ my %opts = (
+ 'iptables' => $iptables_bin,
+ 'iptout' => '/tmp/iptables.out',
+ 'ipterr' => '/tmp/iptables.err',
+ 'debug' => 0,
+ 'verbose' => 0
+ );
+
+ my $ipt_obj = new IPTables::Parse(%opts)
+ or die "[*] Could not acquire IPTables::Parse object";
+
+ &chain_policy_tests($ipt_obj, \%iptables_chains);
+ &chain_rules_tests($ipt_obj, \%iptables_chains);
+ &default_log_tests($ipt_obj);
+ &default_drop_tests($ipt_obj);
+
+ return;
+}
+
+sub ip6tables_tests() {
+
+ &logr("\n[+] Running $ip6tables_bin tests...\n");
+ my %opts = (
+ 'ip6tables' => $ip6tables_bin,
+ 'iptout' => '/tmp/ip6tables.out',
+ 'ipterr' => '/tmp/ip6tables.err',
+ 'debug' => 0,
+ 'verbose' => 0
+ );
+
+ my $ipt_obj = new IPTables::Parse(%opts)
+ or die "[*] Could not acquire IPTables::Parse object";
+
+ &chain_policy_tests($ipt_obj, \%ip6tables_chains);
+ &chain_rules_tests($ipt_obj, \%ip6tables_chains);
+ &default_log_tests($ipt_obj);
+ &default_drop_tests($ipt_obj);
+
+ return;
+}
+
+sub default_log_tests() {
+ my $ipt_obj = shift;
+
+ for my $chain (qw/INPUT OUTPUT FORWARD/) {
+ &dots_print("default_log(): filter $chain");
+
+ my ($ipt_log, $rv) = $ipt_obj->default_log('filter', $chain);
+ $executed++;
+ if ($rv) {
+ &logr("pass ($executed) (found)\n");
+ $passed++;
+ } else {
+ &logr("fail ($executed) (not found)\n");
+ $failed++;
+ }
+ }
+ return;
+}
+
+sub default_drop_tests() {
+ my $ipt_obj = shift;
+
+ for my $chain (qw/INPUT OUTPUT FORWARD/) {
+ &dots_print("default_drop(): filter $chain");
+
+ my ($ipt_drop, $rv) = $ipt_obj->default_drop('filter', $chain);
+ $executed++;
+ if ($rv) {
+ &logr("pass ($executed) (found)\n");
+ $passed++;
+ } else {
+ &logr("fail ($executed) (not found)\n");
+ $failed++;
+ }
+ }
+ return;
+}
+
+sub chain_policy_tests() {
+ my ($ipt_obj, $tables_chains_hr) = @_;
+
+ for my $table (keys %$tables_chains_hr) {
+ for my $chain (@{$tables_chains_hr->{$table}}) {
+ &dots_print("chain_policy(): $table $chain policy");
+
+ my $target = $ipt_obj->chain_policy($table, $chain);
+
+ $executed++;
+
+ if (defined $targets{$target}) {
+ &logr("pass ($executed) ($target)\n");
+ $passed++;
+ } else {
+ &logr("fail ($executed) ($target)\n");
+ &logr(" Unrecognized target '$target'\n");
+ $failed++;
+ }
+ }
+ }
+
+ return;
+}
+
+sub chain_rules_tests() {
+ my ($ipt_obj, $tables_chains_hr) = @_;
+
+ for my $table (keys %$tables_chains_hr) {
+ for my $chain (@{$tables_chains_hr->{$table}}) {
+ &dots_print("chain_rules(): $table $chain rules");
+
+ my ($rv, $out_ar, $err_ar) = $ipt_obj->exec_iptables(
+ "$ipt_obj->{'_iptables'} -t $table -v -n -L $chain");
+
+ my $rules_ar = $ipt_obj->chain_rules($table, $chain);
+
+ $executed++;
+
+ my $matched_state = 1;
+ for (my $i=2; $i<=$#$out_ar; $i++) {
+ if ($out_ar->[$i] =~ /\sctstate/) {
+ unless (defined $rules_ar->[$i-2]->{'ctstate'}
+ and $rules_ar->[$i-2]->{'ctstate'}) {
+ $matched_state = 0;
+ last;
+ }
+ } elsif ($out_ar->[$i] =~ /\sstate/) {
+ unless (defined $rules_ar->[$i-2]->{'state'}
+ and $rules_ar->[$i-2]->{'state'}) {
+ $matched_state = 0;
+ last;
+ }
+ }
+ }
+
+ ### compare raw rules list with parsed chain_rules()
+ ### output - basic number check
+ if (($#$out_ar - 2) == $#$rules_ar and $matched_state) {
+ &logr("pass ($executed)\n");
+ $passed++;
+ } else {
+ &logr("fail ($executed)\n");
+ if ($matched_state) {
+ &logr(" chain_rules() missed extended state info.\n");
+ } else {
+ if (($#$out_ar - 2) > $#$rules_ar) {
+ &logr(" chain_rules() missed rules.\n");
+ } elsif (($#$out_ar - 2) < $#$rules_ar) {
+ &logr(" chain_rules() added inappropriate rules.\n");
+ }
+ }
+ $failed++;
+ }
+ }
+ }
+
+ return;
+}
+
+sub dots_print() {
+ my $msg = shift;
+ &logr($msg);
+ my $dots = '';
+ for (my $i=length($msg); $i < $PRINT_LEN; $i++) {
+ $dots .= '.';
+ }
+ &logr($dots);
+ return;
+}
+
+sub logr() {
+ my $msg = shift;
+ print STDOUT $msg;
+ open F, ">> $logfile" or die $!;
+ print F $msg;
+ close F;
+ return;
+}
+
+sub init() {
+
+ $|++; ### turn off buffering
+
+ $< == 0 && $> == 0 or
+ die "[*] $0: You must be root (or equivalent ",
+ "UID 0 account) to effectively test fwknop";
+
+ unlink $logfile if -e $logfile;
+ for my $bin ($iptables_bin, $ip6tables_bin) {
+ die "[*] $bin does not exist" unless -e $bin;
+ die "[*] $bin not executable" unless -x $bin;
+ }
+
+ return;
+}