]> git.proxmox.com Git - pve-firewall.git/blobdiff - src/PVE/FirewallSimulator.pm
make verbose a global state
[pve-firewall.git] / src / PVE / FirewallSimulator.pm
index 4042ace0377c885740bf19f7edf8cccb0ad78888..188c38fa52325e79f9a3d5cf40a887eddf83d9f1 100644 (file)
@@ -7,10 +7,26 @@ use PVE::Firewall;
 use File::Basename;
 use Net::IP;
 
-my $mark;
+# dynamically include PVE::QemuServer and PVE::LXC
+# to avoid dependency problems
+my $have_qemu_server;
+eval {
+    require PVE::QemuServer;
+    $have_qemu_server = 1;
+};
+
+my $have_lxc;
+eval {
+    require PVE::LXC;
+    $have_lxc = 1;
+};
+
+my $mark = 0;
 my $trace;
 my $debug = 0;
 
+my $NUMBER_RE = qr/0x[0-9a-fA-F]+|\d+/;
+
 sub debug {
     my $new_value = shift;
 
@@ -95,7 +111,7 @@ sub ipset_match {
 sub rule_match {
     my ($ipset_ruleset, $chain, $rule, $pkg) = @_;
 
-    $rule =~ s/^-A $chain // || die "got strange rule: $rule";
+    $rule =~ s/^-A $chain +// || die "got strange rule: $rule";
 
     while (length($rule)) {
 
@@ -209,15 +225,17 @@ sub rule_match {
            next;
        }
 
-       if ($rule =~ s/^-m mark --mark (\d+)\s*//) {
-           return undef if !defined($mark) || $mark != $1;
+       if ($rule =~ s@^-m mark --mark ($NUMBER_RE)(?:/($NUMBER_RE))?\s*@@) {
+           my ($value, $mask) = PVE::Firewall::get_mark_values($1, $2);
+           return undef if ($mark & $mask) != $value;
            next;
        }
 
        # final actions
 
-       if ($rule =~ s/^-j MARK --set-mark (\d+)\s*$//) {
-           $mark = $1;
+       if ($rule =~ s@^-j MARK --set-mark ($NUMBER_RE)(?:/($NUMBER_RE))?\s*$@@) {
+           my ($value, $mask) = PVE::Firewall::get_mark_values($1, $2);
+           $mark = ($mark & ~$mask) | $value;
            return undef;
        }
 
@@ -346,12 +364,7 @@ sub route_packet {
                $pkg->{iface_out} = $target->{bridge} || die 'internal error';
                $chain = 'PVEFW-OUTPUT';
                $next_route_state = $target->{iface} || die 'internal error';
-           } elsif ($target->{type} eq 'ct') {
-               $pkg->{iface_in} = 'lo';
-               $pkg->{iface_out} = 'venet0';
-               $chain = 'PVEFW-OUTPUT';
-               $next_route_state = 'venet-in';
-           } elsif ($target->{type} eq 'vm') {
+           } elsif ($target->{type} eq 'vm' || $target->{type} eq 'ct') {
                $pkg->{iface_in} = 'lo';
                $pkg->{iface_out} = $target->{bridge} || die 'internal error';
                $chain = 'PVEFW-OUTPUT';
@@ -360,40 +373,6 @@ sub route_packet {
                die "implement me";
            }
 
-       } elsif ($route_state eq 'venet-out') {
-
-           if ($target->{type} eq 'host') {
-
-               $chain = 'PVEFW-INPUT';
-               $pkg->{iface_in} = 'venet0';
-               $pkg->{iface_out} = 'lo';
-               $next_route_state = 'host';
-
-           } elsif ($target->{type} eq 'bport') {
-               
-               $chain = 'PVEFW-FORWARD';
-               $pkg->{iface_in} = 'venet0';
-               $pkg->{iface_out} = $target->{bridge} || die 'internal error';
-               $next_route_state = $target->{iface} || die 'internal error';
-
-           } elsif ($target->{type} eq 'vm') {
-
-               $chain = 'PVEFW-FORWARD';
-               $pkg->{iface_in} = 'venet0';
-               $pkg->{iface_out} = $target->{bridge} || die 'internal error';
-               $next_route_state = 'fwbr-in';
-
-           } elsif ($target->{type} eq 'ct') {
-
-               $chain = 'PVEFW-FORWARD';
-               $pkg->{iface_in} = 'venet0';
-               $pkg->{iface_out} = 'venet0';
-               $next_route_state = 'venet-in';
-
-           } else {
-               die "implement me";
-           }
-
        } elsif ($route_state eq 'fwbr-out') {
 
            $chain = 'PVEFW-FORWARD';
@@ -436,14 +415,7 @@ sub route_packet {
                }
                $next_route_state = $target->{iface};
 
-           } elsif ($target->{type} eq 'ct') {
-
-               $chain = 'PVEFW-FORWARD';
-               $pkg->{iface_in} = $route_state;
-               $pkg->{iface_out} = 'venet0';
-               $next_route_state = 'venet-in';
-
-           } elsif ($target->{type} eq 'vm') {
+           } elsif ($target->{type} eq 'vm' || $target->{type} eq 'ct') {
 
                $chain = 'PVEFW-FORWARD';
                $pkg->{iface_in} = $route_state;
@@ -482,16 +454,20 @@ sub route_packet {
 }
 
 sub extract_ct_info {
-    my ($vmdata, $vmid) = @_;
+    my ($vmdata, $vmid, $netnum) = @_;
 
     my $info = { type => 'ct', vmid => $vmid };
 
-    my $conf = $vmdata->{openvz}->{$vmid} || die "no such CT '$vmid'";
-    if ($conf->{ip_address}) {
-       $info->{ip_address} = $conf->{ip_address}->{value};
-    } else {
-       die "implement me";
-    }
+    my $conf = $vmdata->{lxc}->{$vmid} || die "no such CT '$vmid'";
+    my $net = PVE::LXC::Config->parse_lxc_network($conf->{"net$netnum"});
+    $info->{macaddr} = $net->{hwaddr} || die "unable to get mac address";
+    $info->{bridge} = $net->{bridge} || die "unable to get bridge";
+    $info->{fwbr} = "fwbr${vmid}i$netnum";
+    $info->{tapdev} = "veth${vmid}i$netnum";
+    $info->{fwln} = "fwln${vmid}i$netnum";
+    $info->{fwpr} = "fwpr${vmid}p$netnum";
+    $info->{ip_address} = $net->{ip} || die "unable to get ip address";
+
     return $info;
 }
 
@@ -566,15 +542,13 @@ sub simulate_firewall {
        $from_info->{iface} = 'tapXYZ';
        $start_state = 'from-bport';
     } elsif ($from =~ m/^ct(\d+)$/) {
+       return 'SKIPPED' if !$have_lxc;
        my $vmid = $1;
-       $from_info = extract_ct_info($vmdata, $vmid);
-       if ($from_info->{ip_address}) {
-           $pkg->{source} = $from_info->{ip_address} if !defined($pkg->{source});
-           $start_state = 'venet-out';
-       } else {
-           die "implement me";
-       }
+       $from_info = extract_ct_info($vmdata, $vmid, 0);
+       $start_state = 'fwbr-out'; 
+       $pkg->{mac_source} = $from_info->{macaddr};
     } elsif ($from =~ m/^vm(\d+)(i(\d))?$/) {
+       return 'SKIPPED' if !$have_qemu_server;
        my $vmid = $1;
        my $netnum = $3 || 0;
        $from_info = extract_vm_info($vmdata, $vmid, $netnum);
@@ -603,16 +577,12 @@ sub simulate_firewall {
        $target->{bridge} = 'vmbr0';
        $target->{iface} = 'tapXYZ';
     } elsif ($to =~ m/^ct(\d+)$/) {
+       return 'SKIPPED' if !$have_lxc;
        my $vmid = $1;
-       $target = extract_ct_info($vmdata, $vmid);
-       $target->{iface} = 'venet-in';
-
-       if ($target->{ip_address}) {
-           $pkg->{dest} = $target->{ip_address};
-       } else {
-           die "implement me";
-       }
+       $target = extract_ct_info($vmdata, $vmid, 0);
+       $target->{iface} = $target->{tapdev};
    } elsif ($to =~ m/^vm(\d+)$/) {
+       return 'SKIPPED' if !$have_qemu_server;
        my $vmid = $1;
        $target = extract_vm_info($vmdata, $vmid, 0);
        $target->{iface} = $target->{tapdev};