bypass PVEFW-VENET-IN|OUT for unfirewalled venet0 ips
[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, $ipset_ruleset) = PVE::Firewall::compile();
64
65 if ($param->{verbose}) {
66 my (undef, 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, $ipset_ruleset) = PVE::Firewall::compile();
119
120 my (undef, 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