]> git.proxmox.com Git - pve-firewall.git/blobdiff - PVE/Firewall.pm
host firewall support
[pve-firewall.git] / PVE / Firewall.pm
index 4bf4284048f96b8686cef2df9ea2344da7b012a3..de25b045bd897b5ad9892180aa820b46c76b61b8 100644 (file)
@@ -99,27 +99,36 @@ sub get_etc_protocols {
 sub parse_address_list {
     my ($str) = @_;
 
+    my $nbaor = 0;
     foreach my $aor (split(/,/, $str)) {
        if (!Net::IP->new($aor)) {
            my $err = Net::IP::Error();
            die "invalid IP address: $err\n";
+       }else{
+           $nbaor++;
        }
     }
+    return $nbaor;
 }
 
 sub parse_port_name_number_or_range {
     my ($str) = @_;
 
     my $services = PVE::Firewall::get_etc_services();
-
+    my $nbports = 0;
     foreach my $item (split(/,/, $str)) {
+       my $portlist = "";
        foreach my $pon (split(':', $item, 2)) {
-           next if $pon =~ m/^\d+$/ && $pon > 0 && $pon < 65536;
-           next if defined($services->{byname}->{$pon});
-           die "invalid port '$pon'\n";
+           if ($pon =~ m/^\d+$/){
+               die "invalid port '$pon'\n" if $pon < 0 && $pon > 65536;
+           }else{
+               die "invalid port $services->{byname}->{$pon}\n" if !$services->{byname}->{$pon};
+           }
+           $nbports++;
        }
     }
 
+    return ($nbports);
 }
 
 my $rule_format = "%-15s %-30s %-30s %-15s %-15s %-15s\n";
@@ -173,10 +182,14 @@ sub iptables_generate_rule {
 
     my $cmd = "-A $chain";
 
+    $cmd .= " -m iprange --src-range" if $rule->{nbsource} && $rule->{nbsource} > 1;
     $cmd .= " -s $rule->{source}" if $rule->{source};
+    $cmd .= " -m iprange --dst-range" if $rule->{nbdest} && $rule->{nbdest} > 1;
     $cmd .= " -d $rule->{dest}" if $rule->{destination};
     $cmd .= " -p $rule->{proto}" if $rule->{proto};
+    $cmd .= "  --match multiport" if $rule->{nbdport} && $rule->{nbdport} > 1;
     $cmd .= " --dport $rule->{dport}" if $rule->{dport};
+    $cmd .= "  --match multiport" if $rule->{nbsport} && $rule->{nbsport} > 1;
     $cmd .= " --sport $rule->{sport}" if $rule->{sport};
     $cmd .= " -j $rule->{action}" if $rule->{action};
 
@@ -334,6 +347,124 @@ sub flush_tap_rules_direction {
     }
 }
 
+sub enablehostfw {
+
+    generate_proxmoxfwinput();
+    generate_proxmoxfwoutput();
+
+    my $filename = "/etc/pve/local/host.fw";
+    my $fh = IO::File->new($filename, O_RDONLY);
+    return if !$fh;
+
+    my $rules = parse_fw_rules($filename, $fh);
+    my $inrules = $rules->{in};
+    my $outrules = $rules->{out};
+
+    #host inbound firewall
+    iptables_addrule(":host-IN - [0:0]");
+    iptables_addrule("-A host-IN -m state --state INVALID -j DROP");
+    iptables_addrule("-A host-IN -m state --state RELATED,ESTABLISHED -j ACCEPT");
+    iptables_addrule("-A host-IN -i lo -j ACCEPT");
+    iptables_addrule("-A host-IN -m addrtype --dst-type MULTICAST -j ACCEPT");
+    iptables_addrule("-A host-IN -p udp -m state --state NEW -m multiport --dports 5404,5405 -j ACCEPT");
+    iptables_addrule("-A host-IN -p udp -m udp --dport 9000 -j ACCEPT"); #corosync
+
+    if (scalar(@$inrules)) {
+        foreach my $rule (@$inrules) {
+            #we use RETURN because we need to check also tap rules
+            $rule->{action} = 'RETURN' if $rule->{action} eq 'ACCEPT';
+            iptables_generate_rule('host-IN', $rule);
+        }
+    }
+
+    iptables_addrule("-A host-IN -j LOG --log-prefix \"kvmhost-IN dropped: \" --log-level 4");
+    iptables_addrule("-A host-IN -j DROP");
+
+    #host outbound firewall
+    iptables_addrule(":host-OUT - [0:0]");
+    iptables_addrule("-A host-OUT -m state --state INVALID -j DROP");
+    iptables_addrule("-A host-OUT -m state --state RELATED,ESTABLISHED -j ACCEPT");
+    iptables_addrule("-A host-OUT -o lo -j ACCEPT");
+    iptables_addrule("-A host-OUT -m addrtype --dst-type MULTICAST -j ACCEPT");
+    iptables_addrule("-A host-OUT -p udp -m state --state NEW -m multiport --dports 5404,5405 -j ACCEPT");
+    iptables_addrule("-A host-OUT -p udp -m udp --dport 9000 -j ACCEPT"); #corosync
+
+    if (scalar(@$outrules)) {
+        foreach my $rule (@$outrules) {
+            #we use RETURN because we need to check also tap rules
+            $rule->{action} = 'RETURN' if $rule->{action} eq 'ACCEPT';
+            iptables_generate_rule('host-OUT', $rule);
+        }
+    }
+
+    iptables_addrule("-A host-OUT -j LOG --log-prefix \"kvmhost-OUT dropped: \" --log-level 4");
+    iptables_addrule("-A host-OUT -j DROP");
+
+    
+    my $rule = "proxmoxfw-INPUT -j host-IN";
+    if(!iptables_rule_exist($rule)){
+       iptables_addrule("-I $rule");
+    }
+
+    $rule = "proxmoxfw-OUTPUT -j host-OUT";
+    if(!iptables_rule_exist($rule)){
+       iptables_addrule("-I $rule");
+    }
+
+    iptables_restore();
+
+
+}
+
+sub disablehostfw {
+
+    my $chain = "host-IN";
+
+    my $rule = "proxmoxfw-INPUT -j $chain";
+    if(iptables_rule_exist($rule)){
+       iptables_addrule("-D $rule");
+    }
+
+    if(iptables_chain_exist($chain)){
+       iptables_addrule("-F $chain");
+       iptables_addrule("-X $chain");
+    }
+
+    $chain = "host-OUT";
+
+    $rule = "proxmoxfw-OUTPUT -j $chain";
+    if(iptables_rule_exist($rule)){
+       iptables_addrule("-D $rule");
+    }
+
+    if(iptables_chain_exist($chain)){
+       iptables_addrule("-F $chain");
+       iptables_addrule("-X $chain");
+    }
+
+    iptables_restore();   
+}
+
+sub generate_proxmoxfwinput {
+
+    if(!iptables_chain_exist("proxmoxfw-INPUT")){
+        iptables_addrule(":proxmoxfw-INPUT - [0:0]");
+        iptables_addrule("-I INPUT -j proxmoxfw-INPUT");
+        iptables_addrule("-A INPUT -j ACCEPT");
+    }
+}
+
+sub generate_proxmoxfwoutput {
+
+    if(!iptables_chain_exist("proxmoxfw-OUTPUT")){
+        iptables_addrule(":proxmoxfw-OUTPUT - [0:0]");
+        iptables_addrule("-I OUTPUT -j proxmoxfw-OUTPUT");
+        iptables_addrule("-A OUTPUT -j ACCEPT");
+    }
+
+}
+
+
 my $generate_input_rule = sub {
     my ($zoneinfo, $rule, $net, $netid) = @_;
 
@@ -706,12 +837,16 @@ sub parse_fw_rules {
 
        $dport = undef if $dport && $dport eq '-';
        $sport = undef if $sport && $sport eq '-';
+       my $nbdport = undef;
+       my $nbsport = undef;
+       my $nbsource = undef;
+       my $nbdest = undef;
 
        eval {
-           parse_address_list($source) if $source;
-           parse_address_list($dest) if $dest;
-           parse_port_name_number_or_range($dport) if $dport;
-           parse_port_name_number_or_range($sport) if $sport;
+           $nbsource = parse_address_list($source) if $source;
+           $nbdest = parse_address_list($dest) if $dest;
+           $nbdport = parse_port_name_number_or_range($dport) if $dport;
+           $nbsport = parse_port_name_number_or_range($sport) if $sport;
        };
        if (my $err = $@) {
            warn $err;
@@ -726,9 +861,14 @@ sub parse_fw_rules {
            iface => $iface,
            source => $source,
            dest => $dest,
+           nbsource => $nbsource,
+           nbdest => $nbdest,
            proto => $proto,
            dport => $dport,
            sport => $sport,
+           nbdport => $nbdport,
+           nbsport => $nbsport,
+
        };
 
        push @{$res->{$section}}, $rule;