}
}
+sub ruleset_chain_add_conn_filters {
+ my ($ruleset, $chain, $accept) = @_;
+
+ ruleset_addrule($ruleset, $chain, "-m conntrack --ctstate INVALID -j DROP");
+ ruleset_addrule($ruleset, $chain, "-m conntrack --ctstate RELATED,ESTABLISHED -j $accept");
+}
+
+sub ruleset_chain_add_input_filters {
+ my ($ruleset, $chain, $options) = @_;
+
+ if (!(defined($options->{nosmurfs}) && $options->{nosmurfs} == 0)) {
+ ruleset_addrule($ruleset, $chain, "-m conntrack --ctstate INVALID,NEW -j PVEFW-smurfs");
+ }
+
+ if ($options->{tcpflags}) {
+ ruleset_addrule($ruleset, $chain, "-p tcp -j PVEFW-tcpflags");
+ }
+}
+
sub ruleset_create_vm_chain {
my ($ruleset, $chain, $options, $host_options, $macaddr, $direction) = @_;
ruleset_create_chain($ruleset, $chain);
my $accept = generate_nfqueue($options);
- if (!(defined($host_options->{nosmurfs}) && $host_options->{nosmurfs} == 0)) {
- ruleset_addrule($ruleset, $chain, "-m conntrack --ctstate INVALID,NEW -j PVEFW-smurfs");
- }
-
if (!(defined($options->{dhcp}) && $options->{dhcp} == 0)) {
if ($direction eq 'OUT') {
ruleset_generate_rule($ruleset, $chain, { action => 'PVEFW-SET-ACCEPT-MARK',
}
}
- if ($host_options->{tcpflags}) {
- ruleset_addrule($ruleset, $chain, "-p tcp -j PVEFW-tcpflags");
- }
-
- ruleset_addrule($ruleset, $chain, "-m conntrack --ctstate INVALID -j DROP");
- if ($direction eq 'OUT') {
- ruleset_addrule($ruleset, $chain, "-m conntrack --ctstate RELATED,ESTABLISHED -g PVEFW-SET-ACCEPT-MARK");
- } else {
- ruleset_addrule($ruleset, $chain, "-m conntrack --ctstate RELATED,ESTABLISHED -j $accept");
- }
-
if ($direction eq 'OUT') {
if (defined($macaddr) && !(defined($options->{macfilter}) && $options->{macfilter} == 0)) {
ruleset_addrule($ruleset, $chain, "-m mac ! --mac-source $macaddr -j DROP");
my $accept_action = $direction eq 'OUT' ? "PVEFW-SET-ACCEPT-MARK" : $accept;
ruleset_add_chain_policy($ruleset, $chain, $vmid, $policy, $loglevel, $accept_action);
- # plug into FORWARD, INPUT and OUTPUT chain
if ($direction eq 'OUT') {
ruleset_generate_rule_insert($ruleset, "PVEFW-VENET-OUT", {
action => $chain,
source => $ip,
iface_in => 'venet0'});
-
- ruleset_generate_rule_insert($ruleset, "PVEFW-INPUT", {
- action => $chain,
- source => $ip,
- iface_in => 'venet0'});
} else {
ruleset_generate_rule($ruleset, "PVEFW-VENET-IN", {
action => $chain,
dest => $ip,
iface_out => 'venet0'});
-
- ruleset_generate_rule($ruleset, "PVEFW-OUTPUT", {
- action => $chain,
- dest => $ip,
- iface_out => 'venet0'});
}
}
my $loglevel = get_option_log_level($options, "log_level_in");
- if (!(defined($options->{nosmurfs}) && $options->{nosmurfs} == 0)) {
- ruleset_addrule($ruleset, $chain, "-m conntrack --ctstate INVALID,NEW -j PVEFW-smurfs");
- }
+ ruleset_addrule($ruleset, $chain, "-i lo -j ACCEPT");
- if ($options->{tcpflags}) {
- ruleset_addrule($ruleset, $chain, "-p tcp -j PVEFW-tcpflags");
- }
+ ruleset_chain_add_conn_filters($ruleset, $chain, 'ACCEPT');
+ ruleset_chain_add_input_filters($ruleset, $chain, $options);
- ruleset_addrule($ruleset, $chain, "-m conntrack --ctstate INVALID -j DROP");
- ruleset_addrule($ruleset, $chain, "-m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT");
- ruleset_addrule($ruleset, $chain, "-i lo -j ACCEPT");
ruleset_addrule($ruleset, $chain, "-m addrtype --dst-type MULTICAST -j ACCEPT");
ruleset_addrule($ruleset, $chain, "-p udp -m conntrack --ctstate NEW --dport 5404:5405 -j ACCEPT");
ruleset_addrule($ruleset, $chain, "-p udp -m udp --dport 9000 -j ACCEPT"); #corosync
$loglevel = get_option_log_level($options, "log_level_out");
- ruleset_addrule($ruleset, $chain, "-m conntrack --ctstate INVALID -j DROP");
- ruleset_addrule($ruleset, $chain, "-m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT");
ruleset_addrule($ruleset, $chain, "-o lo -j ACCEPT");
+
+ ruleset_chain_add_conn_filters($ruleset, $chain, 'ACCEPT');
+
ruleset_addrule($ruleset, $chain, "-m addrtype --dst-type MULTICAST -j ACCEPT");
ruleset_addrule($ruleset, $chain, "-p udp -m conntrack --ctstate NEW --dport 5404:5405 -j ACCEPT");
ruleset_addrule($ruleset, $chain, "-p udp -m udp --dport 9000 -j ACCEPT"); #corosync
return $vmdata;
};
-sub read_bridges_config {
-
- my $bridgehash = {};
-
- dir_glob_foreach('/sys/class/net', 'vmbr(\d+)', sub {
- my ($bridge) = @_;
-
- dir_glob_foreach("/sys/class/net/$bridge/brif", '((eth|bond)(\d+)(\.(\d+))?)', sub {
- my ($interface) = @_;
- push @{$bridgehash->{$bridge}}, $interface;
- });
- });
-
- return $bridgehash;
-};
-
sub load_vmfw_conf {
- my ($vmid) = @_;
+ my ($vmid, $dir) = @_;
my $vmfw_conf = {};
- my $filename = "/etc/pve/firewall/$vmid.fw";
+ $dir = "/etc/pve/firewall" if !defined($dir);
+
+ my $filename = "$dir/$vmid.fw";
if (my $fh = IO::File->new($filename, O_RDONLY)) {
$vmfw_conf = parse_vm_fw_rules($filename, $fh);
}
}
sub read_vm_firewall_configs {
- my ($vmdata) = @_;
+ my ($vmdata, $dir) = @_;
+
my $vmfw_configs = {};
foreach my $vmid (keys %{$vmdata->{qemu}}, keys %{$vmdata->{openvz}}) {
- my $vmfw_conf = load_vmfw_conf($vmid);
+ my $vmfw_conf = load_vmfw_conf($vmid, $dir);
next if !$vmfw_conf->{options}; # skip if file does not exists
$vmfw_configs->{$vmid} = $vmfw_conf;
}
}
sub load_clusterfw_conf {
+ my ($filename) = @_;
+
+ $filename = $clusterfw_conf_filename if !defined($filename);
my $cluster_conf = {};
- if (my $fh = IO::File->new($clusterfw_conf_filename, O_RDONLY)) {
- $cluster_conf = parse_cluster_fw_rules($clusterfw_conf_filename, $fh);
+ if (my $fh = IO::File->new($filename, O_RDONLY)) {
+ $cluster_conf = parse_cluster_fw_rules($filename, $fh);
}
return $cluster_conf;
}
sub load_hostfw_conf {
+ my ($filename) = @_;
+
+ $filename = $hostfw_conf_filename if !defined($filename);
my $hostfw_conf = {};
- if (my $fh = IO::File->new($hostfw_conf_filename, O_RDONLY)) {
- $hostfw_conf = parse_host_fw_rules($hostfw_conf_filename, $fh);
+ if (my $fh = IO::File->new($filename, O_RDONLY)) {
+ $hostfw_conf = parse_host_fw_rules($filename, $fh);
}
return $hostfw_conf;
}
}
sub compile {
- my ($cluster_conf, $hostfw_conf) = @_;
+ my ($cluster_conf, $hostfw_conf, $vmdata) = @_;
+
+ my $vmfw_configs;
+
+ if ($vmdata) { # test mode
+ my $testdir = $vmdata->{testdir} || die "no test directory specified";
+ my $filename = "$testdir/cluster.fw";
+ die "missing test file '$filename'\n" if ! -f $filename;
+ $cluster_conf = load_clusterfw_conf($filename);
- $cluster_conf = load_clusterfw_conf() if !$cluster_conf;
- $hostfw_conf = load_hostfw_conf() if !$hostfw_conf;
+ $filename = "$testdir/host.fw";
+ die "missing test file '$filename'\n" if ! -f $filename;
+ $hostfw_conf = load_hostfw_conf($filename);
- my $vmdata = read_local_vm_config();
- my $vmfw_configs = read_vm_firewall_configs($vmdata);
+ $vmfw_configs = read_vm_firewall_configs($vmdata, $testdir);
+ } else { # normal operation
+ $cluster_conf = load_clusterfw_conf() if !$cluster_conf;
+
+ $hostfw_conf = load_hostfw_conf() if !$hostfw_conf;
+
+ $vmdata = read_local_vm_config();
+ $vmfw_configs = read_vm_firewall_configs($vmdata);
+ }
- my $bridges_config = read_bridges_config();
my $ipset_ruleset = {};
generate_ipset_chains($ipset_ruleset, $cluster_conf);
ruleset_create_chain($ruleset, "PVEFW-FORWARD");
- ruleset_create_chain($ruleset, "PVEFW-VENET-OUT");
- ruleset_addrule($ruleset, "PVEFW-FORWARD", "-i venet0 -j PVEFW-VENET-OUT");
-
- ruleset_create_chain($ruleset, "PVEFW-FWBR-IN");
- ruleset_addrule($ruleset, "PVEFW-FORWARD", "-m physdev --physdev-is-bridged --physdev-in link+ -j PVEFW-FWBR-IN");
-
- ruleset_create_chain($ruleset, "PVEFW-FWBR-OUT");
- ruleset_addrule($ruleset, "PVEFW-FORWARD", "-m physdev --physdev-is-bridged --physdev-out link+ -j PVEFW-FWBR-OUT");
-
- ruleset_create_chain($ruleset, "PVEFW-VENET-IN");
- ruleset_addrule($ruleset, "PVEFW-FORWARD", "-o venet0 -j PVEFW-VENET-IN");
-
my $hostfw_options = $hostfw_conf->{options} || {};
# fixme: what log level should we use here?
my $loglevel = get_option_log_level($hostfw_options, "log_level_out");
- if($hostfw_options->{optimize}){
-
- my $accept = ruleset_chain_exist($ruleset, "PVEFW-IPS") ? "PVEFW-IPS" : "ACCEPT";
- ruleset_addrule($ruleset, "PVEFW-FORWARD", "-m conntrack --ctstate INVALID -j DROP");
- ruleset_addrule($ruleset, "PVEFW-FORWARD", "-m conntrack --ctstate RELATED,ESTABLISHED -j $accept");
- }
+ ruleset_chain_add_conn_filters($ruleset, "PVEFW-FORWARD", "ACCEPT");
if ($cluster_conf->{ipset}->{blacklist}){
ruleset_addlog($ruleset, "PVEFW-FORWARD", 0, "DROP: ", $loglevel, "-m set --match-set PVEFW-blacklist src");
ruleset_addrule($ruleset, "PVEFW-FORWARD", "-m set --match-set PVEFW-blacklist src -j DROP");
}
+ ruleset_create_chain($ruleset, "PVEFW-VENET-OUT");
+ ruleset_addrule($ruleset, "PVEFW-FORWARD", "-i venet0 -j PVEFW-VENET-OUT");
+ ruleset_addrule($ruleset, "PVEFW-INPUT", "-i venet0 -j PVEFW-VENET-OUT");
+
+ ruleset_create_chain($ruleset, "PVEFW-FWBR-IN");
+ ruleset_chain_add_input_filters($ruleset, "PVEFW-FWBR-IN", $hostfw_options);
+
+ ruleset_addrule($ruleset, "PVEFW-FORWARD", "-m physdev --physdev-is-bridged --physdev-in fwln+ -j PVEFW-FWBR-IN");
+
+ ruleset_create_chain($ruleset, "PVEFW-FWBR-OUT");
+ ruleset_addrule($ruleset, "PVEFW-FORWARD", "-m physdev --physdev-is-bridged --physdev-out fwln+ -j PVEFW-FWBR-OUT");
+
+ ruleset_create_chain($ruleset, "PVEFW-VENET-IN");
+ ruleset_chain_add_input_filters($ruleset, "PVEFW-VENET-IN", $hostfw_options);
+
+ ruleset_addrule($ruleset, "PVEFW-FORWARD", "-o venet0 -j PVEFW-VENET-IN");
+
generate_std_chains($ruleset, $hostfw_options);
my $hostfw_enable = !(defined($hostfw_options->{enable}) && ($hostfw_options->{enable} == 0));
enable_host_firewall($ruleset, $hostfw_conf, $cluster_conf) if $hostfw_enable;
+ ruleset_addrule($ruleset, "PVEFW-OUTPUT", "-o venet0 -j PVEFW-VENET-IN");
+
# generate firewall rules for QEMU VMs
foreach my $vmid (keys %{$vmdata->{qemu}}) {
my $conf = $vmdata->{qemu}->{$vmid};
if ($conf->{ip_address} && $conf->{ip_address}->{value}) {
my $ip = $conf->{ip_address}->{value};
+ $ip =~ s/\s/,/g;
generate_venet_rules_direction($ruleset, $cluster_conf, $hostfw_conf, $vmfw_conf, $vmid, $ip, 'IN');
generate_venet_rules_direction($ruleset, $cluster_conf, $hostfw_conf, $vmfw_conf, $vmid, $ip, 'OUT');
}
}
}
+ if(ruleset_chain_exist($ruleset, "PVEFW-IPS")){
+ ruleset_insertrule($ruleset, "PVEFW-FORWARD", "-m conntrack --ctstate RELATED,ESTABLISHED -j PVEFW-IPS");
+ }
+
return ($ruleset, $ipset_ruleset);
}