#!/usr/bin/perl -T use strict; use warnings; use lib qw(.); use PVE::Firewall; use PVE::SafeSyslog; use PVE::Cluster; use PVE::INotify; use PVE::RPCEnvironment; use PVE::JSONSchema qw(get_standard_option); use PVE::CLIHandler; use base qw(PVE::CLIHandler); $ENV{'PATH'} = '/sbin:/bin:/usr/sbin:/usr/bin'; initlog ('pvefw'); die "please run as root\n" if $> != 0; PVE::INotify::inotify_init(); my $rpcenv = PVE::RPCEnvironment->init('cli'); $rpcenv->init_request(); $rpcenv->set_language($ENV{LANG}); $rpcenv->set_user('root@pam'); __PACKAGE__->register_method ({ name => 'compile', path => 'compile', method => 'POST', description => "Compile amd print firewall rules. This is only for testing.", parameters => { additionalProperties => 0, properties => { verbose => { description => "Verbose output.", type => "boolean", optional => 1, }, }, }, returns => { type => 'null' }, code => sub { my ($param) = @_; my $rpcenv = PVE::RPCEnvironment::get(); $param->{verbose} = 1 if !defined($param->{verbose}) && ($rpcenv->{type} eq 'cli'); my $code = sub { my $ruleset = PVE::Firewall::compile(); PVE::Firewall::get_ruleset_status($ruleset, 1) if $param->{verbose}; }; PVE::Firewall::run_locked($code); return undef; }}); __PACKAGE__->register_method ({ name => 'status', path => 'status', method => 'GET', description => "Get firewall status.", parameters => { additionalProperties => 0, properties => {}, }, returns => { type => 'object', additionalProperties => 0, properties => { status => { type => 'string', enum => ['unknown', 'stopped', 'active'], }, changes => { description => "Set when there are pending changes.", type => 'boolean', optional => 1, } }, }, code => sub { my ($param) = @_; my $rpcenv = PVE::RPCEnvironment::get(); $param->{verbose} = 1 if !defined($param->{verbose}) && ($rpcenv->{type} eq 'cli'); my $code = sub { my $status = PVE::Firewall::read_pvefw_status(); my $res = { status => $status }; if ($status eq 'active') { my $ruleset = PVE::Firewall::compile(); my $cmdlist = PVE::Firewall::get_rulset_cmdlist($ruleset); if ($cmdlist ne "*filter\nCOMMIT\n") { $res->{changes} = 1; } } return $res; }; return PVE::Firewall::run_locked($code); }}); __PACKAGE__->register_method ({ name => 'start', path => 'start', method => 'POST', description => "Start (or simply update if already active) firewall.", parameters => { additionalProperties => 0, properties => { verbose => { description => "Verbose output.", type => "boolean", optional => 1, default => 0, }, }, }, returns => { type => 'null' }, code => sub { my ($param) = @_; PVE::Firewall::update(1, $param->{verbose}); return undef; }}); __PACKAGE__->register_method ({ name => 'update', path => 'update', method => 'POST', description => "Check firewall rules. Then update the rules if the firewall is active.", parameters => { additionalProperties => 0, properties => { verbose => { description => "Verbose output.", type => "boolean", optional => 1, default => 0, }, }, }, returns => { type => 'null' }, code => sub { my ($param) = @_; PVE::Firewall::update(0, $param->{verbose}); return undef; }}); __PACKAGE__->register_method ({ name => 'stop', path => 'stop', method => 'POST', description => "Stop firewall. This will remove all rules installed by this script. The host is then unprotected.", parameters => { additionalProperties => 0, properties => {}, }, returns => { type => 'null' }, code => sub { my ($param) = @_; my $code = sub { my $chash = PVE::Firewall::iptables_get_chains(); my $cmdlist = "*filter\n"; my $rule = "INPUT -j PVEFW-INPUT"; if (PVE::Firewall::iptables_rule_exist($rule)) { $cmdlist .= "-D $rule\n"; } $rule = "OUTPUT -j PVEFW-OUTPUT"; if (PVE::Firewall::iptables_rule_exist($rule)) { $cmdlist .= "-D $rule\n"; } $rule = "FORWARD -j PVEFW-FORWARD"; if (PVE::Firewall::iptables_rule_exist($rule)) { $cmdlist .= "-D $rule\n"; } foreach my $chain (keys %$chash) { $cmdlist .= "-F $chain\n"; } foreach my $chain (keys %$chash) { $cmdlist .= "-X $chain\n"; } $cmdlist .= "COMMIT\n"; PVE::Firewall::iptables_restore_cmdlist($cmdlist); PVE::Firewall::save_pvefw_status('stopped'); }; PVE::Firewall::run_locked($code); return undef; }}); my $nodename = PVE::INotify::nodename(); my $cmddef = { compile => [ __PACKAGE__, 'compile', []], start => [ __PACKAGE__, 'start', []], update => [ __PACKAGE__, 'update', []], status => [ __PACKAGE__, 'status', [], undef, sub { my $res = shift; if ($res->{changes}) { print "Status: $res->{status} (pending changes)\n"; } else { print "Status: $res->{status}\n"; } }], stop => [ __PACKAGE__, 'stop', []], }; my $cmd = shift; PVE::CLIHandler::handle_cmd($cmddef, "pvefw", $cmd, \@ARGV, undef, $0); exit(0);