bump version to 4.1-2
[pve-firewall.git] / test / fwtester.pl
1 #!/usr/bin/perl
2
3 use lib '../src';
4
5 use strict;
6 use warnings;
7
8 use Data::Dumper;
9 use File::Basename;
10 use Getopt::Long;
11 use Net::IP;
12
13 use PVE::Corosync;
14 use PVE::FirewallSimulator;
15 use PVE::INotify;
16
17 my $debug = 0;
18
19 sub print_usage_and_exit {
20     die "usage: $0 [--debug] [testfile [testid]]\n";
21 }
22
23 if (!GetOptions ('debug' => \$debug)) {
24     print_usage_and_exit();
25 }
26
27 # load dummy corosync config to have fw create according rules
28 my $corosync_conf_fn = "corosync.conf";
29 my $raw = PVE::Tools::file_get_contents($corosync_conf_fn);
30 my $local_hostname = PVE::INotify::nodename();
31 (my $raw_replaced = $raw) =~ s/proxself$/$local_hostname\n/gm;
32 my $corosync_conf = PVE::Corosync::parse_conf($corosync_conf_fn, $raw_replaced);
33
34 PVE::FirewallSimulator::debug($debug);
35
36 my $testfilename = shift;
37 my $testid = shift;
38
39 sub run_tests {
40     my ($vmdata, $testdir, $testfile, $testid) = @_;
41
42     $testfile = 'tests' if !$testfile;
43
44
45     $vmdata->{testdir} = $testdir;
46
47     my $host_ip = '172.16.1.2';
48
49     PVE::Firewall::local_network('172.16.1.0/24');
50
51     my ($ruleset, $ipset_ruleset) = 
52         PVE::Firewall::compile(undef, undef, $vmdata, $corosync_conf);
53
54     my $filename = "$testdir/$testfile";
55     my $fh = IO::File->new($filename) ||
56         die "unable to open '$filename' - $!\n";
57
58     my $testcount = 0;
59     while (defined(my $line = <$fh>)) {
60         next if $line =~ m/^\s*$/;
61         next if $line =~ m/^#.*$/;
62         if ($line =~ m/^\{.*\}\s*$/) {
63             my $test = eval $line;
64             die $@ if $@;
65             next if defined($testid) && (!defined($test->{id}) || ($testid ne $test->{id}));
66             PVE::FirewallSimulator::reset_trace();
67             print Dumper($ruleset->{filter}) if $debug;
68             $testcount++;
69             eval {
70                 my @test_zones = qw(host outside nfvm vm100 ct200);
71                 if (!defined($test->{from}) && !defined($test->{to})) {
72                     die "missing zone speification (from, to)\n";
73                 } elsif (!defined($test->{to})) {
74                     foreach my $zone (@test_zones) {
75                         next if $zone eq $test->{from};
76                         $test->{to} = $zone;
77                         PVE::FirewallSimulator::add_trace("Set Zone: to => '$zone'\n"); 
78                         PVE::FirewallSimulator::simulate_firewall($ruleset->{filter}, $ipset_ruleset, 
79                                                                   $host_ip, $vmdata, $test);
80                     }
81                 } elsif (!defined($test->{from})) {
82                     foreach my $zone (@test_zones) {
83                         next if $zone eq $test->{to};
84                         $test->{from} = $zone;
85                         PVE::FirewallSimulator::add_trace("Set Zone: from => '$zone'\n"); 
86                         PVE::FirewallSimulator::simulate_firewall($ruleset->{filter}, $ipset_ruleset, 
87                                                                   $host_ip, $vmdata, $test);
88                     }
89                 } else {
90                     PVE::FirewallSimulator::simulate_firewall($ruleset->{filter}, $ipset_ruleset, 
91                                                               $host_ip, $vmdata, $test);
92                 }
93             };
94             if (my $err = $@) {
95
96                 print Dumper($ruleset->{filter}) if !$debug;
97
98                 print PVE::FirewallSimulator::get_trace() . "\n" if !$debug;
99
100                 print "$filename line $.: $line";
101
102                 print "test failed: $err\n";
103
104                 exit(-1);
105             }
106         } else {
107             die "parse error";
108         }
109     }
110
111     die "no tests found\n" if $testcount <= 0;
112
113     print "PASS: $filename\n";
114
115     return undef;
116 }
117
118 my $vmdata = {
119     qemu => {
120         100 => {
121             net0 => "e1000=0E:0B:38:B8:B3:21,bridge=vmbr0,firewall=1",
122             net1 => "e1000=0E:0B:38:B9:B4:21,bridge=vmbr1,firewall=1",
123             net2 => "e1000=0E:0B:38:BA:B4:21,bridge=vmbr2,firewall=1",
124         },
125         101 => {
126             net0 => "e1000=0E:0B:38:B8:B3:22,bridge=vmbr0,firewall=1",
127         },
128         # on bridge vmbr1
129         110 => {
130             net0 => "e1000=0E:0B:38:B8:B4:21,bridge=vmbr1,firewall=1",
131         },
132     },
133     lxc => {
134         200 => {
135             net0 => "name=eth0,hwaddr=0E:18:24:41:2C:43,bridge=vmbr0,firewall=1,ip=10.0.200.1/24",
136         },
137         201 => {
138             net0 => "name=eth0,hwaddr=0E:18:24:41:2C:44,bridge=vmbr0,firewall=1,ip=10.0.200.2/24",
139         },
140     },
141 };
142
143 if ($testfilename) {
144     my $testfile;
145     my $dir;
146
147     if (-d $testfilename) {
148         $dir = $testfilename;
149     } elsif (-f $testfilename) {
150         $dir = dirname($testfilename);
151         $testfile = basename($testfilename);
152     } else {
153         die "no such file/dir '$testfilename'\n"; 
154     }
155
156     run_tests($vmdata, $dir, $testfile, $testid);
157
158 } else { 
159     foreach my $dir (<test-*>) {
160         next if ! -d $dir;
161         run_tests($vmdata, $dir);
162     }
163 }
164
165 print "OK - all tests passed\n";
166
167 exit(0);