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