fix #967: source: dest: limit length
[pve-firewall.git] / src / PVE / API2 / Firewall / Cluster.pm
1 package PVE::API2::Firewall::Cluster;
2
3 use strict;
4 use warnings;
5 use PVE::Exception qw(raise raise_param_exc raise_perm_exc);
6 use PVE::JSONSchema qw(get_standard_option);
7
8 use PVE::Firewall;
9 use PVE::API2::Firewall::Aliases;
10 use PVE::API2::Firewall::Rules;
11 use PVE::API2::Firewall::Groups;
12 use PVE::API2::Firewall::IPSet;
13
14 #fixme: locking?
15
16
17 use base qw(PVE::RESTHandler);
18
19 __PACKAGE__->register_method ({
20 subclass => "PVE::API2::Firewall::Groups",
21 path => 'groups',
22 });
23
24 __PACKAGE__->register_method ({
25 subclass => "PVE::API2::Firewall::ClusterRules",
26 path => 'rules',
27 });
28
29 __PACKAGE__->register_method ({
30 subclass => "PVE::API2::Firewall::ClusterIPSetList",
31 path => 'ipset',
32 });
33
34 __PACKAGE__->register_method ({
35 subclass => "PVE::API2::Firewall::ClusterAliases",
36 path => 'aliases',
37 });
38
39
40 __PACKAGE__->register_method({
41 name => 'index',
42 path => '',
43 method => 'GET',
44 permissions => { user => 'all' },
45 description => "Directory index.",
46 parameters => {
47 additionalProperties => 0,
48 },
49 returns => {
50 type => 'array',
51 items => {
52 type => "object",
53 properties => {},
54 },
55 links => [ { rel => 'child', href => "{name}" } ],
56 },
57 code => sub {
58 my ($param) = @_;
59
60 my $result = [
61 { name => 'aliases' },
62 { name => 'rules' },
63 { name => 'options' },
64 { name => 'groups' },
65 { name => 'ipset' },
66 { name => 'macros' },
67 { name => 'refs' },
68 ];
69
70 return $result;
71 }});
72
73 my $option_properties = $PVE::Firewall::cluster_option_properties;
74
75 my $add_option_properties = sub {
76 my ($properties) = @_;
77
78 foreach my $k (keys %$option_properties) {
79 $properties->{$k} = $option_properties->{$k};
80 }
81
82 return $properties;
83 };
84
85
86 __PACKAGE__->register_method({
87 name => 'get_options',
88 path => 'options',
89 method => 'GET',
90 description => "Get Firewall options.",
91 permissions => {
92 check => ['perm', '/', [ 'Sys.Audit' ]],
93 },
94 parameters => {
95 additionalProperties => 0,
96 },
97 returns => {
98 type => "object",
99 #additionalProperties => 1,
100 properties => $option_properties,
101 },
102 code => sub {
103 my ($param) = @_;
104
105 my $cluster_conf = PVE::Firewall::load_clusterfw_conf();
106
107 return PVE::Firewall::copy_opject_with_digest($cluster_conf->{options});
108 }});
109
110
111 __PACKAGE__->register_method({
112 name => 'set_options',
113 path => 'options',
114 method => 'PUT',
115 description => "Set Firewall options.",
116 protected => 1,
117 permissions => {
118 check => ['perm', '/', [ 'Sys.Modify' ]],
119 },
120 parameters => {
121 additionalProperties => 0,
122 properties => &$add_option_properties({
123 delete => {
124 type => 'string', format => 'pve-configid-list',
125 description => "A list of settings you want to delete.",
126 optional => 1,
127 },
128 digest => get_standard_option('pve-config-digest'),
129 }),
130 },
131 returns => { type => "null" },
132 code => sub {
133 my ($param) = @_;
134
135 PVE::Firewall::lock_clusterfw_conf(10, sub {
136 my $cluster_conf = PVE::Firewall::load_clusterfw_conf();
137
138 my (undef, $digest) = PVE::Firewall::copy_opject_with_digest($cluster_conf->{options});
139 PVE::Tools::assert_if_modified($digest, $param->{digest});
140
141 if ($param->{delete}) {
142 foreach my $opt (PVE::Tools::split_list($param->{delete})) {
143 raise_param_exc({ delete => "no such option '$opt'" })
144 if !$option_properties->{$opt};
145 delete $cluster_conf->{options}->{$opt};
146 }
147 }
148
149 if (defined($param->{enable}) && ($param->{enable} > 1)) {
150 $param->{enable} = time();
151 }
152
153 foreach my $k (keys %$option_properties) {
154 next if !defined($param->{$k});
155 $cluster_conf->{options}->{$k} = $param->{$k};
156 }
157
158 PVE::Firewall::save_clusterfw_conf($cluster_conf);
159 });
160
161 # instant firewall update when using double (anti-lockout) API call
162 # -> not waiting for a firewall update at the first (timestamp enable) set
163 if (defined($param->{enable}) && ($param->{enable} > 1)) {
164 PVE::Firewall::update();
165 }
166
167 return undef;
168 }});
169
170 __PACKAGE__->register_method({
171 name => 'get_macros',
172 path => 'macros',
173 method => 'GET',
174 description => "List available macros",
175 permissions => { user => 'all' },
176 parameters => {
177 additionalProperties => 0,
178 },
179 returns => {
180 type => 'array',
181 items => {
182 type => "object",
183 properties => {
184 macro => {
185 description => "Macro name.",
186 type => 'string',
187 },
188 descr => {
189 description => "More verbose description (if available).",
190 type => 'string',
191 }
192 },
193 },
194 },
195 code => sub {
196 my ($param) = @_;
197
198 my $res = [];
199
200 my ($macros, $descr) = PVE::Firewall::get_macros();
201
202 foreach my $macro (keys %$macros) {
203 push @$res, { macro => $macro, descr => $descr->{$macro} || $macro };
204 }
205
206 return $res;
207 }});
208
209 __PACKAGE__->register_method({
210 name => 'refs',
211 path => 'refs',
212 method => 'GET',
213 description => "Lists possible IPSet/Alias reference which are allowed in source/dest properties.",
214 permissions => {
215 check => ['perm', '/', [ 'Sys.Audit' ]],
216 },
217 parameters => {
218 additionalProperties => 0,
219 properties => {
220 type => {
221 description => "Only list references of specified type.",
222 type => 'string',
223 enum => ['alias', 'ipset'],
224 optional => 1,
225 },
226 },
227 },
228 returns => {
229 type => 'array',
230 items => {
231 type => "object",
232 properties => {
233 type => {
234 type => 'string',
235 enum => ['alias', 'ipset'],
236 },
237 name => {
238 type => 'string',
239 },
240 ref => {
241 type => 'string',
242 },
243 comment => {
244 type => 'string',
245 optional => 1,
246 },
247 },
248 },
249 },
250 code => sub {
251 my ($param) = @_;
252
253 my $conf = PVE::Firewall::load_clusterfw_conf();
254
255 my $res = [];
256
257 if (!$param->{type} || $param->{type} eq 'ipset') {
258 foreach my $name (keys %{$conf->{ipset}}) {
259 my $data = {
260 type => 'ipset',
261 name => $name,
262 ref => "+$name",
263 };
264 if (my $comment = $conf->{ipset_comments}->{$name}) {
265 $data->{comment} = $comment;
266 }
267 push @$res, $data;
268 }
269 }
270
271 if (!$param->{type} || $param->{type} eq 'alias') {
272 foreach my $name (keys %{$conf->{aliases}}) {
273 my $e = $conf->{aliases}->{$name};
274 my $data = {
275 type => 'alias',
276 name => $name,
277 ref => $name,
278 };
279 $data->{comment} = $e->{comment} if $e->{comment};
280 push @$res, $data;
281 }
282 }
283
284 return $res;
285 }});
286
287 1;