]> git.proxmox.com Git - pve-firewall.git/commitdiff
implement allow_bridge_route feature
authorDietmar Maurer <dietmar@proxmox.com>
Thu, 6 Mar 2014 08:46:12 +0000 (09:46 +0100)
committerDietmar Maurer <dietmar@proxmox.com>
Thu, 6 Mar 2014 08:46:12 +0000 (09:46 +0100)
example/host.fw
src/PVE/Firewall.pm

index 32311b4b55be163893291dbbed71b6f4088978ae..79a59492b1aa1168086b20156493bb1bb7651d05 100644 (file)
@@ -12,8 +12,13 @@ log_level_out: info
 policy_in: DROP
 policy_out: ACCEPT
 
 policy_in: DROP
 policy_out: ACCEPT
 
+# allow more connections (default is 65536)
 nf_conntrack_max: 196608
 
 nf_conntrack_max: 196608
 
+# Enable firewall when bridges contains IP address.
+# The firewall is not fully functional in that case, so
+# you need to enable that explicitly
+allow_bridge_route: 1
 
 [RULES]
 
 
 [RULES]
 
index 0f8ab646679afa52b43ecc943db8569c34d4631b..8c871826a4d433975799b9a95aeb0c5244da77db 100644 (file)
@@ -846,7 +846,12 @@ sub ruleset_insertrule {
 }
 
 sub generate_bridge_chains {
 }
 
 sub generate_bridge_chains {
-    my ($ruleset, $hostfw_conf, $bridge) = @_;
+    my ($ruleset, $hostfw_conf, $bridge, $routing_table) = @_;
+
+    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");
 
     if (!ruleset_chain_exist($ruleset, "$bridge-FW")) {
        ruleset_create_chain($ruleset, "$bridge-FW");
@@ -1309,7 +1314,7 @@ sub parse_hostfw_option {
 
     my $loglevels = "emerg|alert|crit|err|warning|notice|info|debug|nolog";
 
 
     my $loglevels = "emerg|alert|crit|err|warning|notice|info|debug|nolog";
 
-    if ($line =~ m/^(enable|dhcp|nosmurfs|tcpflags):\s*(0|1)\s*$/i) {
+    if ($line =~ m/^(enable|dhcp|nosmurfs|tcpflags|allow_bridge_route):\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) {
        $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) {
@@ -1601,10 +1606,40 @@ sub read_pvefw_status {
     return $status;
 }
 
     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 compile {
     my $vmdata = read_local_vm_config();
     my $vmfw_configs = read_vm_firewall_configs($vmdata);
 
 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 = {};
     my $filename = "/etc/pve/firewall/groups.fw";
     if (my $fh = IO::File->new($filename, O_RDONLY)) {
     my $groups_conf = {};
     my $filename = "/etc/pve/firewall/groups.fw";
     if (my $fh = IO::File->new($filename, O_RDONLY)) {
@@ -1651,7 +1686,7 @@ sub compile {
 
            $bridge .= "v$net->{tag}" if $net->{tag};
 
 
            $bridge .= "v$net->{tag}" if $net->{tag};
 
-           generate_bridge_chains($ruleset, $hostfw_conf, $bridge);
+           generate_bridge_chains($ruleset, $hostfw_conf, $bridge, $routing_table);
 
            my $macaddr = $net->{macaddr};
            generate_tap_rules_direction($ruleset, $groups_conf, $iface, $netid, $macaddr, $vmfw_conf, $bridge, 'IN');
 
            my $macaddr = $net->{macaddr};
            generate_tap_rules_direction($ruleset, $groups_conf, $iface, $netid, $macaddr, $vmfw_conf, $bridge, 'IN');
@@ -1682,6 +1717,9 @@ sub compile {
                    warn "no bridge device for CT $vmid iface '$netid'\n";
                    next; # fixme?
                }
                    warn "no bridge device for CT $vmid iface '$netid'\n";
                    next; # fixme?
                }
+               
+               generate_bridge_chains($ruleset, $hostfw_conf, $bridge, $routing_table);
+
                my $macaddr = $d->{host_mac};
                my $iface = $d->{host_ifname};
                generate_tap_rules_direction($ruleset, $groups_conf, $iface, $netid, $macaddr, $vmfw_conf, $bridge, 'IN');
                my $macaddr = $d->{host_mac};
                my $iface = $d->{host_ifname};
                generate_tap_rules_direction($ruleset, $groups_conf, $iface, $netid, $macaddr, $vmfw_conf, $bridge, 'IN');