From 5e1267a55ed38388206bc1116b7b68775e8caf72 Mon Sep 17 00:00:00 2001 From: Dietmar Maurer Date: Fri, 10 Aug 2012 12:14:33 +0200 Subject: [PATCH] cleanups --- PVE/Firewall.pm | 146 +++++++++++++++++++++++++++++++++++++++++++- README | 29 ++++++++- pvefw | 158 +++++++----------------------------------------- 3 files changed, 192 insertions(+), 141 deletions(-) diff --git a/PVE/Firewall.pm b/PVE/Firewall.pm index 7ff4ddf..8eb277c 100644 --- a/PVE/Firewall.pm +++ b/PVE/Firewall.pm @@ -5,6 +5,9 @@ use strict; use Data::Dumper; use PVE::Tools; use PVE::QemuServer; +use File::Path; +use IO::File; +use Data::Dumper; my $macros; sub get_shorewall_macros { @@ -82,7 +85,7 @@ my $generate_output_rule = sub { # we need complete VM configuration of all VMs (openvz/qemu) # in vmdata -sub compile { +my $compile_shorewall = sub { my ($targetdir, $vmdata, $rules) = @_; # remove existing data ? @@ -318,12 +321,151 @@ sub compile { } PVE::Tools::file_set_contents("$targetdir/rules", $out); +}; + + +sub parse_fw_rules { + my ($filename, $fh) = @_; + + my $section; + + my $res = { in => [], out => [] }; + + my $macros = PVE::Firewall::get_shorewall_macros(); + + while (defined(my $line = <$fh>)) { + next if $line =~ m/^#/; + next if $line =~ m/^\s*$/; + + if ($line =~ m/^\[(in|out)\]\s*$/i) { + $section = lc($1); + next; + } + next if !$section; + + my ($action, $iface, $source, $dest, $proto, $dport, $sport) = + split(/\s+/, $line); + + if (!$action) { + warn "skip incomplete line\n"; + next; + } + + my $service; + if ($action =~ m/^(ACCEPT|DROP|REJECT)$/) { + # OK + } elsif ($action =~ m/^(\S+)\((ACCEPT|DROP|REJECT)\)$/) { + ($service, $action) = ($1, $2); + if (!$macros->{$service}) { + warn "unknown service '$service'\n"; + next; + } + } else { + warn "unknown action '$action'\n"; + next; + } + + $iface = undef if $iface && $iface eq '-'; + if ($iface && $iface !~ m/^(net0|net1|net2|net3|net4|net5)$/) { + warn "unknown interface '$iface'\n"; + next; + } + + $proto = undef if $proto && $proto eq '-'; + if ($proto && $proto !~ m/^(icmp|tcp|udp)$/) { + warn "unknown protokol '$proto'\n"; + next; + } + + $source = undef if $source && $source eq '-'; + +# if ($source !~ m/^(XYZ)$/) { +# warn "unknown source '$source'\n"; +# next; +# } + + $dest = undef if $dest && $dest eq '-'; +# if ($dest !~ m/^XYZ)$/) { +# warn "unknown destination '$dest'\n"; +# next; +# } + + $dport = undef if $dport && $dport eq '-'; + $sport = undef if $sport && $sport eq '-'; + + my $rule = { + action => $action, + service => $service, + iface => $iface, + source => $source, + dest => $dest, + proto => $proto, + dport => $dport, + sport => $sport, + }; + + push @{$res->{$section}}, $rule; + } + + return $res; +} + +sub read_local_vm_config { + + my $openvz = {}; + + my $qemu = {}; + + my $list = PVE::QemuServer::config_list(); + + foreach my $vmid (keys %$list) { + # next if $vmid ne '100'; + my $cfspath = PVE::QemuServer::cfs_config_path($vmid); + if (my $conf = PVE::Cluster::cfs_read_file($cfspath)) { + $qemu->{$vmid} = $conf; + } + } + + my $vmdata = { openvz => $openvz, qemu => $qemu }; + + return $vmdata; +}; + +sub read_vm_firewall_rules { + my ($vmdata) = @_; + my $rules = {}; + foreach my $vmid (keys %{$vmdata->{qemu}}, keys %{$vmdata->{openvz}}) { + my $filename = "/etc/pve/firewall/$vmid.fw"; + my $fh = IO::File->new($filename, O_RDONLY); + next if !$fh; + + $rules->{$vmid} = parse_fw_rules($filename, $fh); + } + + return $rules; +} + +sub compile { + + my $vmdata = read_local_vm_config(); + my $rules = read_vm_firewall_rules($vmdata); + + # print Dumper($vmdata); + + my $swdir = '/etc/shorewall'; + mkdir $swdir; + + &$compile_shorewall($swdir, $vmdata, $rules); + PVE::Tools::run_command(['shorewall', 'compile']); } +sub compile_and_start { + my ($restart) = @_; -sub activate { + compile(); + PVE::Tools::run_command(['shorewall', $restart ? 'restart' : 'start']); } diff --git a/README b/README index b9a9da7..41c7c19 100644 --- a/README +++ b/README @@ -1,13 +1,38 @@ Experimental software, only used for testing. +Note: you need to change values in /etc/sysctl.d/pve.conf to: + +net.bridge.bridge-nf-call-ip6tables = 1 +net.bridge.bridge-nf-call-iptables = 1 +net.bridge.bridge-nf-call-arptables = 1 +net.bridge.bridge-nf-filter-vlan-tagged = 1 + +and reboot after that change. + + VM firewall rules are read from /etc/pve/firewall/.fw You can find examples in the example/ dir +Note: All commands overwrites /etc/shorewall/, so don't use if you have +and existing shorewall config you want to keep. + Use the following command to generate shorewall configuration: ./pvefw compile -That command overwrites /etc/shorewall/, so don't use if you have -and existing shorewall config you want to keep. +To compile and start the firewall: + +./pvefw start + +To compile and restart the firewall: + +./pvefw restart + +To stop the firewall: + +./pvefw stop + +To clear all iptable rules: +./pvefw clear \ No newline at end of file diff --git a/pvefw b/pvefw index 4ac9679..b10895e 100755 --- a/pvefw +++ b/pvefw @@ -3,15 +3,11 @@ use strict; use lib qw(.); use PVE::Firewall; -use File::Path; -use IO::File; -use Data::Dumper; use PVE::SafeSyslog; use PVE::Cluster; use PVE::INotify; use PVE::RPCEnvironment; -use PVE::QemuServer; use PVE::JSONSchema qw(get_standard_option); @@ -34,127 +30,6 @@ $rpcenv->set_language($ENV{LANG}); $rpcenv->set_user('root@pam'); -sub parse_fw_rules { - my ($filename, $fh) = @_; - - my $section; - - my $res = { in => [], out => [] }; - - my $macros = PVE::Firewall::get_shorewall_macros(); - - while (defined(my $line = <$fh>)) { - next if $line =~ m/^#/; - next if $line =~ m/^\s*$/; - - if ($line =~ m/^\[(in|out)\]\s*$/i) { - $section = lc($1); - next; - } - next if !$section; - - my ($action, $iface, $source, $dest, $proto, $dport, $sport) = - split(/\s+/, $line); - - if (!$action) { - warn "skip incomplete line\n"; - next; - } - - my $service; - if ($action =~ m/^(ACCEPT|DROP|REJECT)$/) { - # OK - } elsif ($action =~ m/^(\S+)\((ACCEPT|DROP|REJECT)\)$/) { - ($service, $action) = ($1, $2); - if (!$macros->{$service}) { - warn "unknown service '$service'\n"; - next; - } - } else { - warn "unknown action '$action'\n"; - next; - } - - $iface = undef if $iface && $iface eq '-'; - if ($iface && $iface !~ m/^(net0|net1|net2|net3|net4|net5)$/) { - warn "unknown interface '$iface'\n"; - next; - } - - $proto = undef if $proto && $proto eq '-'; - if ($proto && $proto !~ m/^(icmp|tcp|udp)$/) { - warn "unknown protokol '$proto'\n"; - next; - } - - $source = undef if $source && $source eq '-'; - -# if ($source !~ m/^(XYZ)$/) { -# warn "unknown source '$source'\n"; -# next; -# } - - $dest = undef if $dest && $dest eq '-'; -# if ($dest !~ m/^XYZ)$/) { -# warn "unknown destination '$dest'\n"; -# next; -# } - - $dport = undef if $dport && $dport eq '-'; - $sport = undef if $sport && $sport eq '-'; - - my $rule = { - action => $action, - service => $service, - iface => $iface, - source => $source, - dest => $dest, - proto => $proto, - dport => $dport, - sport => $sport, - }; - - push @{$res->{$section}}, $rule; - } - - return $res; -} - -sub read_local_vm_config { - - my $openvz = {}; - - my $qemu = {}; - - my $list = PVE::QemuServer::config_list(); - - foreach my $vmid (keys %$list) { - # next if $vmid ne '100'; - my $cfspath = PVE::QemuServer::cfs_config_path($vmid); - if (my $conf = PVE::Cluster::cfs_read_file($cfspath)) { - $qemu->{$vmid} = $conf; - } - } - - my $vmdata = { openvz => $openvz, qemu => $qemu }; - - return $vmdata; -}; - -sub read_vm_firewall_rules { - my ($vmdata) = @_; - my $rules = {}; - foreach my $vmid (keys %{$vmdata->{qemu}}, keys %{$vmdata->{openvz}}) { - my $filename = "/etc/pve/firewall/$vmid.fw"; - my $fh = IO::File->new($filename, O_RDONLY); - next if !$fh; - - $rules->{$vmid} = parse_fw_rules($filename, $fh); - } - - return $rules; -} - __PACKAGE__->register_method ({ name => 'compile', path => 'compile', @@ -169,27 +44,35 @@ __PACKAGE__->register_method ({ code => sub { my ($param) = @_; - my $vmdata = read_local_vm_config(); - my $rules = read_vm_firewall_rules($vmdata); + PVE::Firewall::compile(); - # print Dumper($vmdata); + return undef; + }}); - my $swdir = '/etc/shorewall'; - mkdir $swdir; +__PACKAGE__->register_method ({ + name => 'start', + path => 'start', + method => 'POST', + description => "Start firewall.", + parameters => { + additionalProperties => 0, + properties => {}, + }, + returns => { type => 'null' }, - PVE::Firewall::compile($swdir, $vmdata, $rules); + code => sub { + my ($param) = @_; - PVE::Tools::run_command(['shorewall', 'compile']); + PVE::Firewall::compile_and_start(); return undef; - }}); __PACKAGE__->register_method ({ - name => 'start', - path => 'start', + name => 'restart', + path => 'restart', method => 'POST', - description => "Start firewall.", + description => "Restart firewall.", parameters => { additionalProperties => 0, properties => {}, @@ -199,7 +82,7 @@ __PACKAGE__->register_method ({ code => sub { my ($param) = @_; - PVE::Tools::run_command(['shorewall', 'start']); + PVE::Firewall::compile_and_start(1); return undef; }}); @@ -247,6 +130,7 @@ my $nodename = PVE::INotify::nodename(); my $cmddef = { compile => [ __PACKAGE__, 'compile', []], start => [ __PACKAGE__, 'start', []], + restart => [ __PACKAGE__, 'restart', []], stop => [ __PACKAGE__, 'stop', []], clear => [ __PACKAGE__, 'clear', []], }; -- 2.39.2