6dd1aafdb1eb9d8e595610f70e4057f1db610428
[pve-firewall.git] / src / pvefw
1 #!/usr/bin/perl -T
2
3 use strict;
4 use warnings;
5
6 use lib qw(.);
7 use PVE::Firewall;
8
9 use PVE::SafeSyslog;
10 use PVE::Cluster;
11 use PVE::INotify;
12 use PVE::RPCEnvironment;
13
14 use PVE::JSONSchema qw(get_standard_option);
15
16 use PVE::CLIHandler;
17 use PVE::API2::Firewall::Groups;
18
19 use base qw(PVE::CLIHandler);
20
21 use Data::Dumper;
22
23 $ENV{'PATH'} = '/sbin:/bin:/usr/sbin:/usr/bin';
24
25 initlog ('pvefw');
26
27 die "please run as root\n" if $> != 0;
28
29 PVE::INotify::inotify_init();
30
31 my $rpcenv = PVE::RPCEnvironment->init('cli');
32
33 $rpcenv->init_request();
34 $rpcenv->set_language($ENV{LANG});
35 $rpcenv->set_user('root@pam');
36
37 __PACKAGE__->register_method ({
38     name => 'compile',
39     path => 'compile',
40     method => 'POST',
41     description => "Compile amd print firewall rules. This is only for testing.",
42     parameters => {
43         additionalProperties => 0,
44         properties => {
45             verbose => {
46                 description => "Verbose output.",
47                 type => "boolean",
48                 optional => 1,
49             },
50         },
51     },
52     returns => { type => 'null' },
53
54     code => sub {
55         my ($param) = @_;
56
57         my $rpcenv = PVE::RPCEnvironment::get();
58
59         $param->{verbose} = 1 
60             if !defined($param->{verbose}) && ($rpcenv->{type} eq 'cli');
61
62         my $code = sub {
63             my ($ruleset, $hostfw_conf, $ipset_ruleset) = PVE::Firewall::compile();
64
65             if ($param->{verbose}) {
66                 my (undef, $ipset_changes) = PVE::Firewall::get_ipset_cmdlist($ipset_ruleset, 1);
67                 my (undef, $ruleset_changes) = PVE::Firewall::get_ruleset_cmdlist($ruleset, 1);
68                 if ($ipset_changes || $ruleset_changes) {
69                     print "detected changes\n";
70                 } else {
71                     print "no changes\n";
72                 }
73             }
74         };
75
76         PVE::Firewall::run_locked($code);
77
78         return undef;
79     }});
80
81 __PACKAGE__->register_method ({
82     name => 'status',
83     path => 'status',
84     method => 'GET',
85     description => "Get firewall status.",
86     parameters => {
87         additionalProperties => 0,
88         properties => {},
89     },
90     returns => { 
91         type => 'object',
92         additionalProperties => 0,
93         properties => {
94             status => {
95                 type => 'string',
96                 enum => ['unknown', 'stopped', 'active'],
97             },
98             changes => {
99                 description => "Set when there are pending changes.",
100                 type => 'boolean',
101                 optional => 1,
102             }
103         },
104     },
105     code => sub {
106         my ($param) = @_;
107
108         my $rpcenv = PVE::RPCEnvironment::get();
109
110         $param->{verbose} = 1 
111             if !defined($param->{verbose}) && ($rpcenv->{type} eq 'cli');
112
113         my $code = sub {
114             my $status = PVE::Firewall::read_pvefw_status();
115
116             my $res = { status => $status };
117             if ($status eq 'active') {
118                 my ($ruleset, $hostfw_conf, $ipset_ruleset) = PVE::Firewall::compile();
119
120                 my (undef, $ipset_changes) = PVE::Firewall::get_ipset_cmdlist($ipset_ruleset);
121                 my (undef, $ruleset_changes) = PVE::Firewall::get_ruleset_cmdlist($ruleset);
122                 # fixme: ipset changes
123                 $res->{changes} = ($ipset_changes || $ruleset_changes) ? 1 : 0;
124             } 
125
126             return $res;
127         };
128
129         return PVE::Firewall::run_locked($code);
130     }});
131
132 __PACKAGE__->register_method ({
133     name => 'start',
134     path => 'start',
135     method => 'POST',
136     description => "Start (or simply update if already active) firewall.",
137     parameters => {
138         additionalProperties => 0,
139         properties => {
140             verbose => {
141                 description => "Verbose output.",
142                 type => "boolean",
143                 optional => 1,
144                 default => 0,
145             },
146         },
147     },
148     returns => { type => 'null' },
149
150     code => sub {
151         my ($param) = @_;
152
153         PVE::Firewall::update(1, $param->{verbose});
154
155         return undef;
156     }});
157
158 __PACKAGE__->register_method ({
159     name => 'update',
160     path => 'update',
161     method => 'POST',
162     description => "Check firewall rules. Then update the rules if the firewall is active.",
163     parameters => {
164         additionalProperties => 0,
165         properties => {
166             verbose => {
167                 description => "Verbose output.",
168                 type => "boolean",
169                 optional => 1,
170                 default => 0,
171             },
172         },
173     },
174     returns => { type => 'null' },
175
176     code => sub {
177         my ($param) = @_;
178
179         PVE::Firewall::update(0, $param->{verbose});
180
181         return undef;
182     }});
183
184 __PACKAGE__->register_method ({
185     name => 'stop',
186     path => 'stop',
187     method => 'POST',
188     description => "Stop firewall. This will remove all rules installed by this script. The host is then unprotected.",
189     parameters => {
190         additionalProperties => 0,
191         properties => {},
192     },
193     returns => { type => 'null' },
194
195     code => sub {
196         my ($param) = @_;
197
198         my $code = sub {
199             PVE::Firewall::remove_pvefw_chains();
200             PVE::Firewall::save_pvefw_status('stopped');
201         };
202
203         PVE::Firewall::run_locked($code);
204
205         return undef;
206     }});
207
208 my $nodename = PVE::INotify::nodename();
209
210 my $cmddef = {
211     compile => [ __PACKAGE__, 'compile', []],
212     start => [ __PACKAGE__, 'start', []],
213     update => [ __PACKAGE__, 'update', []],
214     status => [ __PACKAGE__, 'status', [], undef, sub {
215         my $res = shift;
216         if ($res->{changes}) {
217             print "Status: $res->{status} (pending changes)\n";
218         } else {
219             print "Status: $res->{status}\n";
220         }
221     }],
222     stop => [ __PACKAGE__, 'stop', []],
223
224     # This is for debugging 
225     listgroups => [ 'PVE::API2::Firewall::Groups', 'list', [], 
226                     { node => $nodename }, sub {
227                         my $res = shift;
228                         print Dumper($res);
229                     }],
230     grouprules => [ 'PVE::API2::Firewall::Groups', 'get_rules', ['group'], 
231                     { node => $nodename }, sub {
232                         my $res = shift;
233                         print Dumper($res);
234                     }],
235 };
236
237 my $cmd = shift;
238
239 PVE::CLIHandler::handle_cmd($cmddef, "pvefw", $cmd, \@ARGV, undef, $0);
240
241 exit(0);
242