mirror of
https://git.proxmox.com/git/pve-firewall
synced 2025-10-04 10:00:15 +00:00
compile ebtables rules
-A FORWARD -j PVEFW-FORWARD -A PVEFW-FORWARD -p IPv4 -j ACCEPT #filter mac in iptables for ipv4, so we can speedup rules with conntrack established -A PVEFW-FORWARD -p IPv6 -j ACCEPT -A PVEFW-FORWARD -o fwln+ -j PVEFW-FWBR-OUT -A PVEFW-FWBR-OUT -i tap110i0 -j tap110i0-OUT -A tap110i0-OUT -s ! 36:97:15:91:19:3c -j DROP -A tap110i0-OUT -p ARP -j ACCEPT -A tap110i0-OUT -j DROP -A tap110i0-OUT -j ACCEPT -A PVEFW-FWBR-OUT -i veth130.1 -j veth130.1-OUT -A veth130.1-OUT -s ! 36:95:a9:ae:f5:ec -j DROP -A veth130.1-OUT -j ACCEPT Signed-off-by: Alexandre Derumier <aderumier at odiso.com> Signed-off-by: Wolfgang Bumiller <w.bumiller@proxmox.com> Reviewed-by: Thomas Lamprecht <t.lamprecht@proxmox.com> Tested-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
This commit is contained in:
parent
d50f24ea6d
commit
c5e8b0088f
3
debian/example/100.fw
vendored
3
debian/example/100.fw
vendored
@ -9,6 +9,9 @@ enable: 1
|
|||||||
# disable/enable MAC address filter
|
# disable/enable MAC address filter
|
||||||
macfilter: 0
|
macfilter: 0
|
||||||
|
|
||||||
|
# limit layer2 specific protocols
|
||||||
|
layer2_protocols: ARP,802_1Q,IPX,NetBEUI,PPP
|
||||||
|
|
||||||
# default policy
|
# default policy
|
||||||
policy_in: DROP
|
policy_in: DROP
|
||||||
policy_out: REJECT
|
policy_out: REJECT
|
||||||
|
@ -2548,6 +2548,14 @@ sub parse_fw_rule {
|
|||||||
return $rule;
|
return $rule;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sub verify_ethertype {
|
||||||
|
my ($value) = @_;
|
||||||
|
my $types = get_etc_ethertypes();
|
||||||
|
die "unknown ethernet protocol type: $value\n"
|
||||||
|
if !defined($types->{byname}->{$value}) &&
|
||||||
|
!defined($types->{byid}->{$value});
|
||||||
|
}
|
||||||
|
|
||||||
sub parse_vmfw_option {
|
sub parse_vmfw_option {
|
||||||
my ($line) = @_;
|
my ($line) = @_;
|
||||||
|
|
||||||
@ -2567,6 +2575,10 @@ sub parse_vmfw_option {
|
|||||||
} elsif ($line =~ m/^(ips_queues):\s*((\d+)(:(\d+))?)\s*$/i) {
|
} elsif ($line =~ m/^(ips_queues):\s*((\d+)(:(\d+))?)\s*$/i) {
|
||||||
$opt = lc($1);
|
$opt = lc($1);
|
||||||
$value = $2;
|
$value = $2;
|
||||||
|
} elsif ($line =~ m/^(layer2_protocols):\s*(((\S+)[,]?)+)\s*$/i) {
|
||||||
|
$opt = lc($1);
|
||||||
|
$value = $2;
|
||||||
|
verify_ethertype($_) foreach split(/\s*,\s*/, $value);
|
||||||
} else {
|
} else {
|
||||||
die "can't parse option '$line'\n"
|
die "can't parse option '$line'\n"
|
||||||
}
|
}
|
||||||
@ -3380,9 +3392,10 @@ sub compile {
|
|||||||
|
|
||||||
my $ruleset = compile_iptables_filter($cluster_conf, $hostfw_conf, $vmfw_configs, $vmdata, 4, $verbose);
|
my $ruleset = compile_iptables_filter($cluster_conf, $hostfw_conf, $vmfw_configs, $vmdata, 4, $verbose);
|
||||||
my $rulesetv6 = compile_iptables_filter($cluster_conf, $hostfw_conf, $vmfw_configs, $vmdata, 6, $verbose);
|
my $rulesetv6 = compile_iptables_filter($cluster_conf, $hostfw_conf, $vmfw_configs, $vmdata, 6, $verbose);
|
||||||
|
my $ebtables_ruleset = compile_ebtables_filter($cluster_conf, $hostfw_conf, $vmfw_configs, $vmdata, $verbose);
|
||||||
my $ipset_ruleset = compile_ipsets($cluster_conf, $vmfw_configs, $vmdata);
|
my $ipset_ruleset = compile_ipsets($cluster_conf, $vmfw_configs, $vmdata);
|
||||||
|
|
||||||
return ($ruleset, $ipset_ruleset, $rulesetv6);
|
return ($ruleset, $ipset_ruleset, $rulesetv6, $ebtables_ruleset);
|
||||||
}
|
}
|
||||||
|
|
||||||
sub compile_iptables_filter {
|
sub compile_iptables_filter {
|
||||||
@ -3594,6 +3607,94 @@ sub compile_ipsets {
|
|||||||
return $ipset_ruleset;
|
return $ipset_ruleset;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sub compile_ebtables_filter {
|
||||||
|
my ($cluster_conf, $hostfw_conf, $vmfw_configs, $vmdata, $verbose) = @_;
|
||||||
|
|
||||||
|
return ({}, {}) if !$cluster_conf->{options}->{enable};
|
||||||
|
|
||||||
|
my $ruleset = {};
|
||||||
|
|
||||||
|
ruleset_create_chain($ruleset, "PVEFW-FORWARD");
|
||||||
|
|
||||||
|
|
||||||
|
ruleset_create_chain($ruleset, "PVEFW-FWBR-OUT");
|
||||||
|
#for ipv4 and ipv6, check macaddress in iptables, so we use conntrack 'ESTABLISHED', to speedup rules
|
||||||
|
ruleset_addrule($ruleset, 'PVEFW-FORWARD', '-p IPv4', '-j ACCEPT');
|
||||||
|
ruleset_addrule($ruleset, 'PVEFW-FORWARD', '-p IPv6', '-j ACCEPT');
|
||||||
|
ruleset_addrule($ruleset, 'PVEFW-FORWARD', '-o fwln+', '-j PVEFW-FWBR-OUT');
|
||||||
|
|
||||||
|
# generate firewall rules for QEMU VMs
|
||||||
|
foreach my $vmid (keys %{$vmdata->{qemu}}) {
|
||||||
|
eval {
|
||||||
|
my $conf = $vmdata->{qemu}->{$vmid};
|
||||||
|
my $vmfw_conf = $vmfw_configs->{$vmid};
|
||||||
|
return if !$vmfw_conf;
|
||||||
|
|
||||||
|
foreach my $netid (keys %$conf) {
|
||||||
|
next if $netid !~ m/^net(\d+)$/;
|
||||||
|
my $net = PVE::QemuServer::parse_net($conf->{$netid});
|
||||||
|
next if !$net->{firewall};
|
||||||
|
my $iface = "tap${vmid}i$1";
|
||||||
|
my $macaddr = $net->{macaddr};
|
||||||
|
|
||||||
|
generate_tap_layer2filter($ruleset, $iface, $macaddr, $vmfw_conf, $vmid);
|
||||||
|
|
||||||
|
}
|
||||||
|
};
|
||||||
|
warn $@ if $@; # just to be sure - should not happen
|
||||||
|
}
|
||||||
|
|
||||||
|
# generate firewall rules for LXC containers
|
||||||
|
foreach my $vmid (keys %{$vmdata->{lxc}}) {
|
||||||
|
eval {
|
||||||
|
my $conf = $vmdata->{lxc}->{$vmid};
|
||||||
|
|
||||||
|
my $vmfw_conf = $vmfw_configs->{$vmid};
|
||||||
|
return if !$vmfw_conf || !$vmfw_conf->{options}->{enable};
|
||||||
|
|
||||||
|
foreach my $netid (keys %$conf) {
|
||||||
|
next if $netid !~ m/^net(\d+)$/;
|
||||||
|
my $net = PVE::LXC::Config->parse_lxc_network($conf->{$netid});
|
||||||
|
next if !$net->{firewall};
|
||||||
|
my $iface = "veth${vmid}i$1";
|
||||||
|
my $macaddr = $net->{hwaddr};
|
||||||
|
generate_tap_layer2filter($ruleset, $iface, $macaddr, $vmfw_conf, $vmid);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
warn $@ if $@; # just to be sure - should not happen
|
||||||
|
}
|
||||||
|
|
||||||
|
return $ruleset;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub generate_tap_layer2filter {
|
||||||
|
my ($ruleset, $iface, $macaddr, $vmfw_conf, $vmid) = @_;
|
||||||
|
my $options = $vmfw_conf->{options};
|
||||||
|
|
||||||
|
my $tapchain = $iface."-OUT";
|
||||||
|
|
||||||
|
# ebtables remove zeros from mac pairs
|
||||||
|
$macaddr =~ s/0([0-9a-f])/$1/ig;
|
||||||
|
$macaddr = lc($macaddr);
|
||||||
|
|
||||||
|
ruleset_create_chain($ruleset, $tapchain);
|
||||||
|
|
||||||
|
if (defined($macaddr) && !(defined($options->{macfilter}) && $options->{macfilter} == 0)) {
|
||||||
|
ruleset_addrule($ruleset, $tapchain, "-s ! $macaddr", '-j DROP');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (defined($options->{layer2_protocols})){
|
||||||
|
foreach my $proto (split(/,/, $options->{layer2_protocols})) {
|
||||||
|
ruleset_addrule($ruleset, $tapchain, "-p $proto", '-j ACCEPT');
|
||||||
|
}
|
||||||
|
ruleset_addrule($ruleset, $tapchain, '', "-j DROP");
|
||||||
|
} else {
|
||||||
|
ruleset_addrule($ruleset, $tapchain, '', '-j ACCEPT');
|
||||||
|
}
|
||||||
|
|
||||||
|
ruleset_addrule($ruleset, 'PVEFW-FWBR-OUT', "-i $iface", "-j $tapchain");
|
||||||
|
}
|
||||||
|
|
||||||
sub get_ruleset_status {
|
sub get_ruleset_status {
|
||||||
my ($ruleset, $active_chains, $digest_fn, $verbose) = @_;
|
my ($ruleset, $active_chains, $digest_fn, $verbose) = @_;
|
||||||
|
|
||||||
@ -3947,7 +4048,7 @@ sub update {
|
|||||||
|
|
||||||
my $hostfw_conf = load_hostfw_conf($cluster_conf);
|
my $hostfw_conf = load_hostfw_conf($cluster_conf);
|
||||||
|
|
||||||
my ($ruleset, $ipset_ruleset, $rulesetv6) = compile($cluster_conf, $hostfw_conf);
|
my ($ruleset, $ipset_ruleset, $rulesetv6, $ebtables_ruleset) = compile($cluster_conf, $hostfw_conf);
|
||||||
|
|
||||||
apply_ruleset($ruleset, $hostfw_conf, $ipset_ruleset, $rulesetv6);
|
apply_ruleset($ruleset, $hostfw_conf, $ipset_ruleset, $rulesetv6);
|
||||||
};
|
};
|
||||||
|
@ -164,7 +164,7 @@ __PACKAGE__->register_method ({
|
|||||||
|
|
||||||
if ($status eq 'running') {
|
if ($status eq 'running') {
|
||||||
|
|
||||||
my ($ruleset, $ipset_ruleset, $rulesetv6) = PVE::Firewall::compile($cluster_conf, undef, undef, $verbose);
|
my ($ruleset, $ipset_ruleset, $rulesetv6, $ebtables_ruleset) = PVE::Firewall::compile($cluster_conf, undef, undef, $verbose);
|
||||||
|
|
||||||
$verbose = 0; # do not show iptables details
|
$verbose = 0; # do not show iptables details
|
||||||
my (undef, undef, $ipset_changes) = PVE::Firewall::get_ipset_cmdlist($ipset_ruleset, $verbose);
|
my (undef, undef, $ipset_changes) = PVE::Firewall::get_ipset_cmdlist($ipset_ruleset, $verbose);
|
||||||
@ -201,7 +201,7 @@ __PACKAGE__->register_method ({
|
|||||||
my $verbose = 1;
|
my $verbose = 1;
|
||||||
|
|
||||||
my $cluster_conf = PVE::Firewall::load_clusterfw_conf(undef, $verbose);
|
my $cluster_conf = PVE::Firewall::load_clusterfw_conf(undef, $verbose);
|
||||||
my ($ruleset, $ipset_ruleset, $rulesetv6) = PVE::Firewall::compile($cluster_conf, undef, undef, $verbose);
|
my ($ruleset, $ipset_ruleset, $rulesetv6, $ebtables_ruleset) = PVE::Firewall::compile($cluster_conf, undef, undef, $verbose);
|
||||||
|
|
||||||
print "ipset cmdlist:\n";
|
print "ipset cmdlist:\n";
|
||||||
my (undef, undef, $ipset_changes) = PVE::Firewall::get_ipset_cmdlist($ipset_ruleset, $verbose);
|
my (undef, undef, $ipset_changes) = PVE::Firewall::get_ipset_cmdlist($ipset_ruleset, $verbose);
|
||||||
@ -329,7 +329,7 @@ __PACKAGE__->register_method ({
|
|||||||
|
|
||||||
local $SIG{'__WARN__'} = 'DEFAULT'; # do not fill up syslog
|
local $SIG{'__WARN__'} = 'DEFAULT'; # do not fill up syslog
|
||||||
|
|
||||||
my ($ruleset, $ipset_ruleset, $rulesetv6) = PVE::Firewall::compile(undef, undef, undef, $param->{verbose});
|
my ($ruleset, $ipset_ruleset, $rulesetv6, $ebtables_ruleset) = PVE::Firewall::compile(undef, undef, undef, $param->{verbose});
|
||||||
|
|
||||||
PVE::FirewallSimulator::debug($param->{verbose} || 0);
|
PVE::FirewallSimulator::debug($param->{verbose} || 0);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user