#!/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 PVE::API2::Firewall::Groups; use base qw(PVE::CLIHandler); use Data::Dumper; $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, $ipset_ruleset) = PVE::Firewall::compile(); if ($param->{verbose}) { my (undef, undef, $ipset_changes) = PVE::Firewall::get_ipset_cmdlist($ipset_ruleset, 1); my (undef, $ruleset_changes) = PVE::Firewall::get_ruleset_cmdlist($ruleset, 1); if ($ipset_changes || $ruleset_changes) { print "detected changes\n"; } else { print "no changes\n"; } } }; 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, $ipset_ruleset) = PVE::Firewall::compile(); my (undef, undef, $ipset_changes) = PVE::Firewall::get_ipset_cmdlist($ipset_ruleset); my (undef, $ruleset_changes) = PVE::Firewall::get_ruleset_cmdlist($ruleset); # fixme: ipset changes $res->{changes} = ($ipset_changes || $ruleset_changes) ? 1 : 0; } 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 { PVE::Firewall::remove_pvefw_chains(); 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', []], # This is for debugging listgroups => [ 'PVE::API2::Firewall::Groups', 'list', [], { node => $nodename }, sub { my $res = shift; print Dumper($res); }], grouprules => [ 'PVE::API2::Firewall::Groups', 'get_rules', ['group'], { node => $nodename }, sub { my $res = shift; print Dumper($res); }], }; my $cmd = shift; PVE::CLIHandler::handle_cmd($cmddef, "pvefw", $cmd, \@ARGV, undef, $0); exit(0);