maxLength => 20,
});
+PVE::JSONSchema::register_standard_option('pve-fw-alias', {
+ description => "Alias name.",
+ type => 'string',
+ pattern => '[A-Za-z][A-Za-z0-9\-\_]+',
+ minLength => 2,
+ maxLength => 20,
+});
+
PVE::JSONSchema::register_standard_option('pve-fw-loglevel' => {
description => "Log level.",
type => 'string',
$sha->add($k, ':', $v, "\n");
}
- my $digest = $sha->b64digest;
+ my $digest = $sha->hexdigest;
$res->{digest} = $digest;
push @$res, $data;
}
- my $digest = $sha->b64digest;
+ my $digest = $sha->hexdigest;
foreach my $entry (@$res) {
$entry->{digest} = $digest;
return 1 if $name =~ m/^venet0-\d+-(:?IN|OUT)$/;
- return 1 if $name =~ m/^vmbr\d+(v\d+)?-(:?FW|IN|OUT|IPS)$/;
+ return 1 if $name =~ m/^fwbr\d+(v\d+)?-(:?FW|IN|OUT|IPS)$/;
return 1 if $name =~ m/^GROUP-(:?[^\s\-]+)-(:?IN|OUT)$/;
return undef;
die "invalid security group name '$source'\n";
}
} elsif ($source =~ m/^${ip_alias_pattern}$/){
- die "no such alias $source\n" if !$cluster_conf->{aliases}->{$source};
- push @cmd, "-s $cluster_conf->{aliases}->{$source}";
-
+ my $alias = lc($source);
+ my $e = $cluster_conf->{aliases}->{$alias};
+ die "no such alias $source\n" if !$e;
+ push @cmd, "-s $e->{cidr}";
} elsif ($source =~ m/\-/){
push @cmd, "-m iprange --src-range $source";
die "invalid security group name '$dest'\n";
}
} elsif ($dest =~ m/^${ip_alias_pattern}$/){
- die "no such alias $dest" if !$cluster_conf->{aliases}->{$dest};
- push @cmd, "-d $cluster_conf->{aliases}->{$dest}";
-
+ my $alias = lc($source);
+ my $e = $cluster_conf->{aliases}->{$alias};
+ die "no such alias $dest" if !$e;
+ push @cmd, "-d $e->{cidr}";
} elsif ($dest =~ m/^(\d+)\.(\d+).(\d+).(\d+)\-(\d+)\.(\d+).(\d+).(\d+)$/){
push @cmd, "-m iprange --dst-range $dest";
$logrule = "$rule $logrule" if defined($rule);
- ruleset_addrule($ruleset, $chain, $logrule)
-}
-
-sub generate_bridge_chains {
- my ($ruleset, $hostfw_conf, $bridge, $routing_table, $bridges_config) = @_;
-
- my $options = $hostfw_conf->{options} || {};
-
- die "error: detected direct route to bridge '$bridge'\n"
- if !$options->{allow_bridge_route} && $routing_table->{$bridge};
-
- if (!ruleset_chain_exist($ruleset, "$bridge-FW")) {
- ruleset_create_chain($ruleset, "$bridge-FW");
- ruleset_addrule($ruleset, "PVEFW-FORWARD", "-o $bridge -m physdev --physdev-is-out -j $bridge-FW");
- ruleset_addrule($ruleset, "PVEFW-FORWARD", "-i $bridge -m physdev --physdev-is-in -j $bridge-FW");
- }
-
- if (!ruleset_chain_exist($ruleset, "$bridge-OUT")) {
- ruleset_create_chain($ruleset, "$bridge-OUT");
-
- if($options->{optimize}){
- foreach my $interface (@{$bridges_config->{$bridge}}) {
- ruleset_addrule($ruleset, "$bridge-OUT", "-m physdev --physdev-is-bridged --physdev-in $interface -g PVEFW-SET-ACCEPT-MARK");
- }
- }
-
- ruleset_addrule($ruleset, "$bridge-FW", "-m physdev --physdev-is-in -j $bridge-OUT");
- ruleset_insertrule($ruleset, "PVEFW-INPUT", "-i $bridge -m physdev --physdev-is-in -j $bridge-OUT");
- }
-
- if (!ruleset_chain_exist($ruleset, "$bridge-IN")) {
- ruleset_create_chain($ruleset, "$bridge-IN");
-
- if($options->{optimize}){
- foreach my $interface (@{$bridges_config->{$bridge}}) {
- ruleset_addrule($ruleset, "$bridge-IN", "-m physdev --physdev-is-bridged --physdev-out $interface -j ACCEPT");
- }
- }
-
- ruleset_addrule($ruleset, "$bridge-FW", "-m physdev --physdev-is-out -j $bridge-IN");
- ruleset_addrule($ruleset, "$bridge-FW", "-m mark --mark 1 -j ACCEPT");
- # accept traffic to unmanaged bridge ports
- ruleset_addrule($ruleset, "$bridge-FW", "-m physdev --physdev-is-out -j ACCEPT ");
- }
+ ruleset_addrule($ruleset, $chain, $logrule);
}
sub ruleset_add_chain_policy {
}
}
+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");
} else {
next if $rule->{type} ne $lc_direction;
- if ($direction eq 'OUT') {
- ruleset_generate_rule($ruleset, $chain, $rule,
- { ACCEPT => "PVEFW-SET-ACCEPT-MARK", REJECT => "PVEFW-reject" }, undef, $cluster_conf);
- } else {
- ruleset_generate_rule($ruleset, $chain, $rule, { ACCEPT => $in_accept , REJECT => "PVEFW-reject" }, undef, $cluster_conf);
- }
+ eval {
+ if ($direction eq 'OUT') {
+ ruleset_generate_rule($ruleset, $chain, $rule,
+ { ACCEPT => "PVEFW-SET-ACCEPT-MARK", REJECT => "PVEFW-reject" },
+ undef, $cluster_conf);
+ } else {
+ ruleset_generate_rule($ruleset, $chain, $rule,
+ { ACCEPT => $in_accept , REJECT => "PVEFW-reject" },
+ undef, $cluster_conf);
+ }
+ };
+ warn $@ if $@;
}
}
}
}
sub ruleset_generate_vm_ipsrules {
- my ($ruleset, $options, $direction, $iface, $bridge) = @_;
+ my ($ruleset, $options, $direction, $iface) = @_;
if ($options->{ips} && $direction eq 'IN') {
my $nfqueue = generate_nfqueue($options);
- if (!ruleset_chain_exist($ruleset, "$bridge-IPS")) {
+ if (!ruleset_chain_exist($ruleset, "PVEFW-IPS")) {
ruleset_create_chain($ruleset, "PVEFW-IPS");
}
- if (!ruleset_chain_exist($ruleset, "$bridge-IPS")) {
- ruleset_create_chain($ruleset, "$bridge-IPS");
- ruleset_insertrule($ruleset, "PVEFW-IPS", "-o $bridge -m physdev --physdev-is-out -j $bridge-IPS");
- }
-
- ruleset_addrule($ruleset, "$bridge-IPS", "-m physdev --physdev-out $iface --physdev-is-bridged -j $nfqueue");
+ ruleset_addrule($ruleset, "PVEFW-IPS", "-m physdev --physdev-out $iface --physdev-is-bridged -j $nfqueue");
}
}
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-FORWARD", {
- action => $chain,
- source => $ip,
- iface_in => 'venet0'});
-
- ruleset_generate_rule_insert($ruleset, "PVEFW-INPUT", {
+ ruleset_generate_rule_insert($ruleset, "PVEFW-VENET-OUT", {
action => $chain,
source => $ip,
iface_in => 'venet0'});
} else {
- ruleset_generate_rule($ruleset, "PVEFW-FORWARD", {
- action => $chain,
- dest => $ip,
- iface_out => 'venet0'});
-
- ruleset_generate_rule($ruleset, "PVEFW-OUTPUT", {
+ ruleset_generate_rule($ruleset, "PVEFW-VENET-IN", {
action => $chain,
dest => $ip,
iface_out => 'venet0'});
}
sub generate_tap_rules_direction {
- my ($ruleset, $cluster_conf, $hostfw_conf, $iface, $netid, $macaddr, $vmfw_conf, $vmid, $bridge, $direction) = @_;
+ my ($ruleset, $cluster_conf, $hostfw_conf, $iface, $netid, $macaddr, $vmfw_conf, $vmid, $direction) = @_;
my $lc_direction = lc($direction);
ruleset_generate_vm_rules($ruleset, $rules, $cluster_conf, $tapchain, $netid, $direction, $options);
- ruleset_generate_vm_ipsrules($ruleset, $options, $direction, $iface, $bridge);
+ ruleset_generate_vm_ipsrules($ruleset, $options, $direction, $iface);
# implement policy
my $policy;
# plug the tap chain to bridge chain
if ($direction eq 'IN') {
- ruleset_addrule($ruleset, "$bridge-IN",
- "-m physdev --physdev-is-bridged --physdev-out $iface -j $tapchain");
+ ruleset_addrule($ruleset, "PVEFW-FWBR-IN",
+ "-m physdev --physdev-is-bridged --physdev-out $iface -j $tapchain");
} else {
- ruleset_addrule($ruleset, "$bridge-OUT",
- "-m physdev --physdev-in $iface -j $tapchain");
+ ruleset_addrule($ruleset, "PVEFW-FWBR-OUT",
+ "-m physdev --physdev-is-bridged --physdev-in $iface -j $tapchain");
}
}
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
my $loglevels = "emerg|alert|crit|err|warning|notice|info|debug|nolog";
- if ($line =~ m/^(enable|nosmurfs|tcpflags|allow_bridge_route|optimize):\s*(0|1)\s*$/i) {
+ if ($line =~ m/^(enable|nosmurfs|tcpflags|optimize):\s*(0|1)\s*$/i) {
$opt = lc($1);
$value = int($2);
} elsif ($line =~ m/^(log_level_in|log_level_out|tcp_flags_log_level|smurf_log_level):\s*(($loglevels)\s*)?$/i) {
sub parse_clusterfw_alias {
my ($line) = @_;
- my ($opt, $value);
+ # we can add single line comments to the end of the line
+ my $comment = decode('utf8', $1) if $line =~ s/\s*#\s*(.*?)\s*$//;
+
if ($line =~ m/^(\S+)\s(\S+)$/) {
- $opt = lc($1);
- if($2){
- $2 =~ s|/32$||;
- pve_verify_ipv4_or_cidr($2) if $2;
- $value = $2;
- }
- } else {
- chomp $line;
- die "can't parse option '$line'\n";
+ my ($name, $cidr) = ($1, $2);
+ $cidr =~ s|/32$||;
+ pve_verify_ipv4_or_cidr($cidr);
+ my $data = {
+ name => $name,
+ cidr => $cidr,
+ };
+ $data->{comment} = $comment if $comment;
+ return $data;
}
- return ($opt, $value);
+ return undef;
}
sub parse_vm_fw_rules {
my $res = {
rules => [],
options => {},
+ aliases => {},
groups => {},
group_comments => {},
ipset => {} ,
warn "$prefix: $@" if $@;
} elsif ($section eq 'aliases') {
eval {
- my ($opt, $value) = parse_clusterfw_alias($line);
- $res->{aliases}->{$opt} = $value;
+ my $data = parse_clusterfw_alias($line);
+ $res->{aliases}->{lc($data->{name})} = $data;
};
warn "$prefix: $@" if $@;
} elsif ($section eq 'rules') {
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);
}
return $raw;
};
+my $format_aliases = sub {
+ my ($aliases) = @_;
+
+ my $raw = '';
+
+ $raw .= "[ALIASES]\n\n";
+ foreach my $k (keys %$aliases) {
+ my $e = $aliases->{$k};
+ $raw .= "$e->{name} $e->{cidr}";
+ $raw .= " # " . encode('utf8', $e->{comment})
+ if $e->{comment} && $e->{comment} !~ m/^\s*$/;
+ $raw .= "\n";
+ }
+ $raw .= "\n";
+
+ return $raw;
+};
+
my $format_ipset = sub {
my ($options) = @_;
my $options = $vmfw_conf->{options};
$raw .= &$format_options($options) if scalar(keys %$options);
- my $rules = $vmfw_conf->{rules};
+ my $rules = $vmfw_conf->{rules} || [];
if (scalar(@$rules)) {
$raw .= "[RULES]\n\n";
$raw .= &$format_rules($rules, 1);
}
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;
}
foreach my $entry (@$options) {
my $cidr = $entry->{cidr};
if ($cidr =~ m/^${ip_alias_pattern}$/) {
- if ($aliases->{$cidr}) {
- $entry->{cidr} = $aliases->{$cidr};
+ my $alias = lc($cidr);
+ if ($aliases->{$alias}) {
+ $entry->{cidr} = $aliases->{$alias}->{cidr};
+ $nethash->{$entry->{cidr}} = $entry;
} else {
- warn "no such alias '$cidr'\n" if !$aliases->{$cidr};
+ warn "no such alias '$cidr'\n" if !$aliases->{$alias};
}
+ } else {
+ $nethash->{$entry->{cidr}} = $entry;
}
- $nethash->{$entry->{cidr}} = $entry;
}
foreach my $cidr (sort keys %$nethash) {
return $status;
}
-# fixme: move to pve-common PVE::ProcFSTools
-sub read_proc_net_route {
- my $filename = "/proc/net/route";
-
- my $res = {};
-
- my $fh = IO::File->new ($filename, "r");
- return $res if !$fh;
-
- my $int_to_quad = sub {
- return join '.' => map { ($_[0] >> 8*(3-$_)) % 256 } (3, 2, 1, 0);
- };
-
- while (defined(my $line = <$fh>)) {
- next if $line =~/^Iface\s+Destination/; # skip head
- my ($iface, $dest, $gateway, $metric, $mask, $mtu) = (split(/\s+/, $line))[0,1,2,6,7,8];
- push @{$res->{$iface}}, {
- dest => &$int_to_quad(hex($dest)),
- gateway => &$int_to_quad(hex($gateway)),
- mask => &$int_to_quad(hex($mask)),
- metric => $metric,
- mtu => $mtu,
- };
- }
-
- return $res;
-}
-
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;
my $options = $cluster_conf->{options};
$raw .= &$format_options($options) if scalar(keys %$options);
+ my $aliases = $cluster_conf->{aliases};
+ $raw .= &$format_aliases($aliases) if scalar(keys %$aliases);
+
foreach my $ipset (sort keys %{$cluster_conf->{ipset}}) {
if (my $comment = $cluster_conf->{ipset_comments}->{$ipset}) {
my $utf8comment = encode('utf8', $comment);
}
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) = @_;
- $cluster_conf = load_clusterfw_conf() if !$cluster_conf;
- $hostfw_conf = load_hostfw_conf() if !$hostfw_conf;
+ my $vmfw_configs;
- my $vmdata = read_local_vm_config();
- my $vmfw_configs = read_vm_firewall_configs($vmdata);
+ 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);
+
+ $filename = "$testdir/host.fw";
+ die "missing test file '$filename'\n" if ! -f $filename;
+ $hostfw_conf = load_hostfw_conf($filename);
+
+ $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 $routing_table = read_proc_net_route();
-
- my $bridges_config = read_bridges_config();
my $ipset_ruleset = {};
generate_ipset_chains($ipset_ruleset, $cluster_conf);
ruleset_create_chain($ruleset, "PVEFW-OUTPUT");
ruleset_create_chain($ruleset, "PVEFW-FORWARD");
-
+
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");
+
+ my $accept = ruleset_chain_exist($ruleset, "PVEFW-IPS") ? "PVEFW-IPS" : "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 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_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};
next if !$net;
my $iface = "tap${vmid}i$1";
- my $bridge = $net->{bridge};
- next if !$bridge; # fixme: ?
-
- $bridge .= "v$net->{tag}" if $net->{tag};
-
- generate_bridge_chains($ruleset, $hostfw_conf, $bridge, $routing_table, $bridges_config);
-
my $macaddr = $net->{macaddr};
generate_tap_rules_direction($ruleset, $cluster_conf, $hostfw_conf, $iface, $netid, $macaddr,
- $vmfw_conf, $vmid, $bridge, 'IN');
+ $vmfw_conf, $vmid, 'IN');
generate_tap_rules_direction($ruleset, $cluster_conf, $hostfw_conf, $iface, $netid, $macaddr,
- $vmfw_conf, $vmid, $bridge, 'OUT');
+ $vmfw_conf, $vmid, 'OUT');
}
}
my $netif = PVE::OpenVZ::parse_netif($conf->{netif}->{value});
foreach my $netid (keys %$netif) {
my $d = $netif->{$netid};
- my $bridge = $d->{bridge};
- if (!$bridge) {
- warn "no bridge device for CT $vmid iface '$netid'\n";
- next; # fixme?
- }
-
- generate_bridge_chains($ruleset, $hostfw_conf, $bridge, $routing_table, $bridges_config);
my $macaddr = $d->{mac};
my $iface = $d->{host_ifname};
generate_tap_rules_direction($ruleset, $cluster_conf, $hostfw_conf, $iface, $netid, $macaddr,
- $vmfw_conf, $vmid, $bridge, 'IN');
+ $vmfw_conf, $vmid, 'IN');
generate_tap_rules_direction($ruleset, $cluster_conf, $hostfw_conf, $iface, $netid, $macaddr,
- $vmfw_conf, $vmid, $bridge, 'OUT');
+ $vmfw_conf, $vmid, 'OUT');
}
}
}
- if($hostfw_options->{optimize}){
-
- my $accept = ruleset_chain_exist($ruleset, "PVEFW-IPS") ? "PVEFW-IPS" : "ACCEPT";
- ruleset_insertrule($ruleset, "PVEFW-FORWARD", "-m conntrack --ctstate RELATED,ESTABLISHED -j $accept");
- ruleset_insertrule($ruleset, "PVEFW-FORWARD", "-m conntrack --ctstate INVALID -j DROP");
- }
-
- # fixme: what log level should we use here?
- my $loglevel = get_option_log_level($hostfw_options, "log_level_out");
-
- # fixme: should we really block inter-bridge traffic?
-
- # always allow traffic from containers?
- ruleset_addrule($ruleset, "PVEFW-FORWARD", "-i venet0 -j RETURN");
-
- # disable interbridge routing
- ruleset_addrule($ruleset, "PVEFW-FORWARD", "-o vmbr+ -j PVEFW-Drop");
- ruleset_addrule($ruleset, "PVEFW-FORWARD", "-i vmbr+ -j PVEFW-Drop");
- ruleset_addlog($ruleset, "PVEFW-FORWARD", 0, "DROP: ", $loglevel, "-o vmbr+");
- ruleset_addlog($ruleset, "PVEFW-FORWARD", 0, "DROP: ", $loglevel, "-i vmbr+");
- ruleset_addrule($ruleset, "PVEFW-FORWARD", "-o vmbr+ -j DROP");
- ruleset_addrule($ruleset, "PVEFW-FORWARD", "-i vmbr+ -j DROP");
-
return ($ruleset, $ipset_ruleset);
}