use PVE::Cluster;
use PVE::ProcFSTools;
use PVE::Tools;
-use PVE::QemuServer;
-use PVE::OpenVZ; # dependeny problem?!
use File::Basename;
use File::Path;
use IO::File;
use Net::IP;
use PVE::Tools qw(run_command lock_file);
-use Data::Dumper;
+# dynamically include PVE::QemuServer and PVE::OpenVZ
+# to avoid dependency problems
+my $have_qemu_server;
+eval {
+ require PVE::QemuServer;
+ $have_qemu_server = 1;
+};
+
+my $have_pve_manager;
+eval {
+ require PVE::OpenVZ;
+ $have_pve_manager = 1;
+};
-# fixme: remove loglevel settings? NFLOG does not have --loglevel
+use Data::Dumper;
my $nodename = PVE::INotify::nodename();
return ($nbports);
}
+# helper function for API
+sub cleanup_fw_rule {
+ my ($rule, $digest, $pos) = @_;
+
+ my $r = {};
+
+ foreach my $k (keys %$rule) {
+ next if $k eq 'nbdport';
+ next if $k eq 'nbsport';
+ my $v = $rule->{$k};
+ next if !defined($v);
+ $r->{$k} = $v;
+ $r->{digest} = $digest;
+ $r->{pos} = $pos;
+ }
+
+ return $r;
+}
+
my $bridge_firewall_enabled = 0;
sub enable_bridge_firewall {
die "no such security group '$group'\n" if !$groups_conf->{$group};
- my $rules = $groups_conf->{$group}->{rules};
+ my $rules = $groups_conf->{rules}->{$group};
my $chain = "GROUP-${group}-IN";
my $section;
+ my $digest = Digest::SHA->new('sha1');
+
while (defined(my $line = <$fh>)) {
+ $digest->add($line);
+
next if $line =~ m/^#/;
next if $line =~ m/^\s*$/;
push @{$res->{$section}}, @$rules;
}
+ $res->{digest} = $digest->b64digest;
+
return $res;
}
my $section;
+ my $digest = Digest::SHA->new('sha1');
+
while (defined(my $line = <$fh>)) {
+ $digest->add($line);
+
next if $line =~ m/^#/;
next if $line =~ m/^\s*$/;
push @{$res->{$section}}, @$rules;
}
+ $res->{digest} = $digest->b64digest;
+
return $res;
}
my $section;
my $group;
- my $res = { rules => [] };
+ my $res = { rules => {} };
+
+ my $digest = Digest::SHA->new('sha1');
while (defined(my $line = <$fh>)) {
+ $digest->add($line);
+
next if $line =~ m/^#/;
next if $line =~ m/^\s*$/;
next;
}
- push @{$res->{$group}->{$section}}, @$rules;
+ push @{$res->{$section}->{$group}}, @$rules;
}
+ $res->{digest} = $digest->b64digest;
+
return $res;
}
next if !$d->{node} || $d->{node} ne $nodename;
next if !$d->{type};
if ($d->{type} eq 'openvz') {
- my $cfspath = PVE::OpenVZ::cfs_config_path($vmid);
- if (my $conf = PVE::Cluster::cfs_read_file($cfspath)) {
- $openvz->{$vmid} = $conf;
+ if ($have_pve_manager) {
+ my $cfspath = PVE::OpenVZ::cfs_config_path($vmid);
+ if (my $conf = PVE::Cluster::cfs_read_file($cfspath)) {
+ $openvz->{$vmid} = $conf;
+ }
}
} elsif ($d->{type} eq 'qemu') {
- my $cfspath = PVE::QemuServer::cfs_config_path($vmid);
- if (my $conf = PVE::Cluster::cfs_read_file($cfspath)) {
- $qemu->{$vmid} = $conf;
+ if ($have_qemu_server) {
+ my $cfspath = PVE::QemuServer::cfs_config_path($vmid);
+ if (my $conf = PVE::Cluster::cfs_read_file($cfspath)) {
+ $qemu->{$vmid} = $conf;
+ }
}
}
}
-
+
return $vmdata;
};
+sub load_vmfw_conf {
+ my ($vmid) = @_;
+
+ my $vmfw_conf = {};
+
+ my $filename = "/etc/pve/firewall/$vmid.fw";
+ if (my $fh = IO::File->new($filename, O_RDONLY)) {
+ $vmfw_conf = parse_vm_fw_rules($filename, $fh);
+ }
+
+ return $vmfw_conf;
+}
+
sub read_vm_firewall_configs {
my ($vmdata) = @_;
my $vmfw_configs = {};
foreach my $vmid (keys %{$vmdata->{qemu}}, keys %{$vmdata->{openvz}}) {
- my $filename = "/etc/pve/firewall/$vmid.fw";
- my $fh = IO::File->new($filename, O_RDONLY);
- next if !$fh;
-
- $vmfw_configs->{$vmid} = parse_vm_fw_rules($filename, $fh);
+ my $vmfw_conf = load_vmfw_conf($vmid);
+ next if !$vmfw_conf->{options}; # skip if file does not exists
+ $vmfw_configs->{$vmid} = $vmfw_conf;
}
return $vmfw_configs;
return $res;
}
-sub compile {
- my $vmdata = read_local_vm_config();
- my $vmfw_configs = read_vm_firewall_configs($vmdata);
-
- my $routing_table = read_proc_net_route();
+sub load_security_groups {
my $groups_conf = {};
my $filename = "/etc/pve/firewall/groups.fw";
$groups_conf = parse_group_fw_rules($filename, $fh);
}
+ return $groups_conf;
+}
+
+sub load_hostfw_conf {
+
+ my $hostfw_conf = {};
+ my $filename = "/etc/pve/local/host.fw";
+ if (my $fh = IO::File->new($filename, O_RDONLY)) {
+ $hostfw_conf = parse_host_fw_rules($filename, $fh);
+ }
+ return $hostfw_conf;
+}
+
+sub compile {
+ my $vmdata = read_local_vm_config();
+ my $vmfw_configs = read_vm_firewall_configs($vmdata);
+
+ my $routing_table = read_proc_net_route();
+
+ my $groups_conf = load_security_groups();
+
my $ruleset = {};
ruleset_create_chain($ruleset, "PVEFW-INPUT");
ruleset_create_chain($ruleset, "PVEFW-FORWARD");
- my $hostfw_options = {};
- my $hostfw_conf = {};
-
- $filename = "/etc/pve/local/host.fw";
- if (my $fh = IO::File->new($filename, O_RDONLY)) {
- $hostfw_conf = parse_host_fw_rules($filename, $fh);
- $hostfw_options = $hostfw_conf->{options};
- }
+ my $hostfw_conf = load_hostfw_conf();
+ my $hostfw_options = $hostfw_conf->{options} || {};
generate_std_chains($ruleset, $hostfw_options);
}
}
- # fixme: this is an optimization? if so, we should also drop INVALID packages?
- ruleset_insertrule($ruleset, "PVEFW-FORWARD", "-m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT");
-
# fixme: what log level should we use here?
my $loglevel = get_option_log_level($hostfw_options, "log_level_out");