]> git.proxmox.com Git - pve-firewall.git/blame - src/PVE/API2/Firewall/IPSet.pm
check ipversion of aliases
[pve-firewall.git] / src / PVE / API2 / Firewall / IPSet.pm
CommitLineData
009ee3ac
DM
1package PVE::API2::Firewall::IPSetBase;
2
3use strict;
4use warnings;
4a11bba5 5use PVE::Exception qw(raise raise_param_exc);
009ee3ac
DM
6use PVE::JSONSchema qw(get_standard_option);
7
8use PVE::Firewall;
9
10use base qw(PVE::RESTHandler);
11
12my $api_properties = {
13 cidr => {
14 description => "Network/IP specification in CIDR format.",
7c619bbb 15 type => 'string', format => 'IPv4orCIDRorAlias',
009ee3ac 16 },
e74a87f5 17 name => get_standard_option('ipset-name'),
009ee3ac
DM
18 comment => {
19 type => 'string',
20 optional => 1,
21 },
22 nomatch => {
23 type => 'boolean',
24 optional => 1,
25 },
26};
27
28sub load_config {
29 my ($class, $param) = @_;
30
31 die "implement this in subclass";
1210ae94
DM
32
33 #return ($cluster_conf, $fw_conf, $ipset);
009ee3ac
DM
34}
35
1210ae94
DM
36sub save_config {
37 my ($class, $param, $fw_conf) = @_;
009ee3ac
DM
38
39 die "implement this in subclass";
40}
41
9f6845cf
DM
42sub rule_env {
43 my ($class, $param) = @_;
44
45 die "implement this in subclass";
46}
47
1210ae94
DM
48sub save_ipset {
49 my ($class, $param, $fw_conf, $ipset) = @_;
50
51 if (!defined($ipset)) {
52 delete $fw_conf->{ipset}->{$param->{name}};
53 } else {
54 $fw_conf->{ipset}->{$param->{name}} = $ipset;
55 }
56
57 $class->save_config($param, $fw_conf);
58}
59
009ee3ac
DM
60my $additional_param_hash = {};
61
62sub additional_parameters {
63 my ($class, $new_value) = @_;
64
65 if (defined($new_value)) {
66 $additional_param_hash->{$class} = $new_value;
67 }
68
69 # return a copy
70 my $copy = {};
71 my $org = $additional_param_hash->{$class} || {};
72 foreach my $p (keys %$org) { $copy->{$p} = $org->{$p}; }
73 return $copy;
74}
75
76sub register_get_ipset {
77 my ($class) = @_;
78
79 my $properties = $class->additional_parameters();
80
81 $properties->{name} = $api_properties->{name};
82
83 $class->register_method({
84 name => 'get_ipset',
85 path => '',
86 method => 'GET',
87 description => "List IPSet content",
9f6845cf 88 permissions => PVE::Firewall::rules_audit_permissions($class->rule_env()),
009ee3ac
DM
89 parameters => {
90 additionalProperties => 0,
91 properties => $properties,
92 },
93 returns => {
94 type => 'array',
95 items => {
96 type => "object",
97 properties => {
98 cidr => {
99 type => 'string',
100 },
101 comment => {
102 type => 'string',
103 optional => 1,
104 },
105 nomatch => {
106 type => 'boolean',
107 optional => 1,
d72c631c
DM
108 },
109 digest => get_standard_option('pve-config-digest', { optional => 0} ),
009ee3ac
DM
110 },
111 },
112 links => [ { rel => 'child', href => "{cidr}" } ],
113 },
114 code => sub {
115 my ($param) = @_;
116
1210ae94 117 my ($cluster_conf, $fw_conf, $ipset) = $class->load_config($param);
009ee3ac 118
5d38d64f 119 return PVE::Firewall::copy_list_with_digest($ipset);
009ee3ac
DM
120 }});
121}
122
1210ae94
DM
123sub register_delete_ipset {
124 my ($class) = @_;
125
126 my $properties = $class->additional_parameters();
127
128 $properties->{name} = get_standard_option('ipset-name');
129
130 $class->register_method({
131 name => 'delete_ipset',
132 path => '',
133 method => 'DELETE',
134 description => "Delete IPSet",
135 protected => 1,
9f6845cf 136 permissions => PVE::Firewall::rules_modify_permissions($class->rule_env()),
1210ae94
DM
137 parameters => {
138 additionalProperties => 0,
139 properties => $properties,
140 },
141 returns => { type => 'null' },
142 code => sub {
143 my ($param) = @_;
144
145 my ($cluster_conf, $fw_conf, $ipset) = $class->load_config($param);
146
147 die "IPSet '$param->{name}' is not empty\n"
148 if scalar(@$ipset);
149
150 $class->save_ipset($param, $fw_conf, undef);
151
152 return undef;
153 }});
154}
155
a33c74f6 156sub register_create_ip {
009ee3ac
DM
157 my ($class) = @_;
158
159 my $properties = $class->additional_parameters();
160
161 $properties->{name} = $api_properties->{name};
162 $properties->{cidr} = $api_properties->{cidr};
163 $properties->{nomatch} = $api_properties->{nomatch};
164 $properties->{comment} = $api_properties->{comment};
d72c631c 165
009ee3ac 166 $class->register_method({
a33c74f6 167 name => 'create_ip',
009ee3ac
DM
168 path => '',
169 method => 'POST',
170 description => "Add IP or Network to IPSet.",
171 protected => 1,
9f6845cf 172 permissions => PVE::Firewall::rules_modify_permissions($class->rule_env()),
009ee3ac
DM
173 parameters => {
174 additionalProperties => 0,
175 properties => $properties,
176 },
177 returns => { type => "null" },
178 code => sub {
179 my ($param) = @_;
180
1210ae94 181 my ($cluster_conf, $fw_conf, $ipset) = $class->load_config($param);
009ee3ac 182
4a11bba5
DM
183 my $cidr = $param->{cidr};
184
185 foreach my $entry (@$ipset) {
186 raise_param_exc({ cidr => "address '$cidr' already exists" })
187 if $entry->{cidr} eq $cidr;
188 }
189
6c221576
DM
190 # make sure alias exists (if $cidr is an alias)
191 PVE::Firewall::resolve_alias($cluster_conf, $fw_conf, $cidr);
7c619bbb 192
4a11bba5 193 my $data = { cidr => $cidr };
7c619bbb 194
009ee3ac
DM
195 $data->{nomatch} = 1 if $param->{nomatch};
196 $data->{comment} = $param->{comment} if $param->{comment};
197
009ee3ac
DM
198 unshift @$ipset, $data;
199
200 $class->save_ipset($param, $fw_conf, $ipset);
201
202 return undef;
203 }});
204}
205
a33c74f6
DM
206sub register_read_ip {
207 my ($class) = @_;
208
209 my $properties = $class->additional_parameters();
210
211 $properties->{name} = $api_properties->{name};
212 $properties->{cidr} = $api_properties->{cidr};
213
214 $class->register_method({
215 name => 'read_ip',
216 path => '{cidr}',
217 method => 'GET',
218 description => "Read IP or Network settings from IPSet.",
9f6845cf 219 permissions => PVE::Firewall::rules_audit_permissions($class->rule_env()),
a33c74f6
DM
220 protected => 1,
221 parameters => {
222 additionalProperties => 0,
223 properties => $properties,
224 },
225 returns => { type => "object" },
226 code => sub {
227 my ($param) = @_;
228
1210ae94 229 my ($cluster_conf, $fw_conf, $ipset) = $class->load_config($param);
a33c74f6 230
5d38d64f
DM
231 my $list = PVE::Firewall::copy_list_with_digest($ipset);
232
233 foreach my $entry (@$list) {
d72c631c 234 if ($entry->{cidr} eq $param->{cidr}) {
d72c631c
DM
235 return $entry;
236 }
a33c74f6
DM
237 }
238
239 raise_param_exc({ cidr => "no such IP/Network" });
240 }});
241}
242
243sub register_update_ip {
244 my ($class) = @_;
245
246 my $properties = $class->additional_parameters();
247
248 $properties->{name} = $api_properties->{name};
249 $properties->{cidr} = $api_properties->{cidr};
250 $properties->{nomatch} = $api_properties->{nomatch};
251 $properties->{comment} = $api_properties->{comment};
d72c631c
DM
252 $properties->{digest} = get_standard_option('pve-config-digest');
253
a33c74f6
DM
254 $class->register_method({
255 name => 'update_ip',
256 path => '{cidr}',
257 method => 'PUT',
258 description => "Update IP or Network settings",
259 protected => 1,
9f6845cf 260 permissions => PVE::Firewall::rules_modify_permissions($class->rule_env()),
a33c74f6
DM
261 parameters => {
262 additionalProperties => 0,
263 properties => $properties,
264 },
265 returns => { type => "null" },
266 code => sub {
267 my ($param) = @_;
268
1210ae94 269 my ($cluster_conf, $fw_conf, $ipset) = $class->load_config($param);
a33c74f6 270
5d38d64f
DM
271 my (undef, $digest) = PVE::Firewall::copy_list_with_digest($ipset);
272 PVE::Tools::assert_if_modified($digest, $param->{digest});
d72c631c 273
a33c74f6
DM
274 foreach my $entry (@$ipset) {
275 if($entry->{cidr} eq $param->{cidr}) {
276 $entry->{nomatch} = $param->{nomatch};
277 $entry->{comment} = $param->{comment};
278 $class->save_ipset($param, $fw_conf, $ipset);
279 return;
280 }
281 }
282
283 raise_param_exc({ cidr => "no such IP/Network" });
284 }});
285}
286
287sub register_delete_ip {
009ee3ac
DM
288 my ($class) = @_;
289
290 my $properties = $class->additional_parameters();
291
292 $properties->{name} = $api_properties->{name};
293 $properties->{cidr} = $api_properties->{cidr};
d72c631c
DM
294 $properties->{digest} = get_standard_option('pve-config-digest');
295
009ee3ac
DM
296 $class->register_method({
297 name => 'remove_ip',
298 path => '{cidr}',
299 method => 'DELETE',
300 description => "Remove IP or Network from IPSet.",
301 protected => 1,
9f6845cf 302 permissions => PVE::Firewall::rules_modify_permissions($class->rule_env()),
009ee3ac
DM
303 parameters => {
304 additionalProperties => 0,
305 properties => $properties,
306 },
307 returns => { type => "null" },
308 code => sub {
309 my ($param) = @_;
310
1210ae94 311 my ($cluster_conf, $fw_conf, $ipset) = $class->load_config($param);
009ee3ac 312
5d38d64f
DM
313 my (undef, $digest) = PVE::Firewall::copy_list_with_digest($ipset);
314 PVE::Tools::assert_if_modified($digest, $param->{digest});
d72c631c 315
4a11bba5
DM
316 my $new = [];
317
318 foreach my $entry (@$ipset) {
319 push @$new, $entry if $entry->{cidr} ne $param->{cidr};
320 }
009ee3ac 321
4a11bba5
DM
322 $class->save_ipset($param, $fw_conf, $new);
323
009ee3ac
DM
324 return undef;
325 }});
326}
327
328sub register_handlers {
329 my ($class) = @_;
330
1210ae94 331 $class->register_delete_ipset();
009ee3ac 332 $class->register_get_ipset();
a33c74f6
DM
333 $class->register_create_ip();
334 $class->register_read_ip();
335 $class->register_update_ip();
336 $class->register_delete_ip();
009ee3ac
DM
337}
338
339package PVE::API2::Firewall::ClusterIPset;
340
341use strict;
342use warnings;
343
344use base qw(PVE::API2::Firewall::IPSetBase);
345
9f6845cf
DM
346sub rule_env {
347 my ($class, $param) = @_;
348
349 return 'cluster';
350}
351
009ee3ac
DM
352sub load_config {
353 my ($class, $param) = @_;
354
355 my $fw_conf = PVE::Firewall::load_clusterfw_conf();
356 my $ipset = $fw_conf->{ipset}->{$param->{name}};
357 die "no such IPSet '$param->{name}'\n" if !defined($ipset);
358
1210ae94 359 return (undef, $fw_conf, $ipset);
009ee3ac
DM
360}
361
1210ae94
DM
362sub save_config {
363 my ($class, $param, $fw_conf) = @_;
009ee3ac 364
009ee3ac
DM
365 PVE::Firewall::save_clusterfw_conf($fw_conf);
366}
367
368__PACKAGE__->register_handlers();
369
1210ae94
DM
370package PVE::API2::Firewall::VMIPset;
371
372use strict;
373use warnings;
374use PVE::JSONSchema qw(get_standard_option);
375
376use base qw(PVE::API2::Firewall::IPSetBase);
377
9f6845cf
DM
378sub rule_env {
379 my ($class, $param) = @_;
380
381 return 'vm';
382}
383
1210ae94
DM
384__PACKAGE__->additional_parameters({
385 node => get_standard_option('pve-node'),
386 vmid => get_standard_option('pve-vmid'),
387});
388
389sub load_config {
390 my ($class, $param) = @_;
391
392 my $cluster_conf = PVE::Firewall::load_clusterfw_conf();
393 my $fw_conf = PVE::Firewall::load_vmfw_conf($cluster_conf, 'vm', $param->{vmid});
394 my $ipset = $fw_conf->{ipset}->{$param->{name}};
395 die "no such IPSet '$param->{name}'\n" if !defined($ipset);
396
397 return ($cluster_conf, $fw_conf, $ipset);
398}
399
400sub save_config {
401 my ($class, $param, $fw_conf) = @_;
402
403 PVE::Firewall::save_vmfw_conf($param->{vmid}, $fw_conf);
404}
405
406__PACKAGE__->register_handlers();
407
408package PVE::API2::Firewall::CTIPset;
409
410use strict;
411use warnings;
412use PVE::JSONSchema qw(get_standard_option);
413
414use base qw(PVE::API2::Firewall::IPSetBase);
415
9f6845cf
DM
416sub rule_env {
417 my ($class, $param) = @_;
418
419 return 'ct';
420}
421
1210ae94
DM
422__PACKAGE__->additional_parameters({
423 node => get_standard_option('pve-node'),
424 vmid => get_standard_option('pve-vmid'),
425});
426
427sub load_config {
428 my ($class, $param) = @_;
429
430 my $cluster_conf = PVE::Firewall::load_clusterfw_conf();
431 my $fw_conf = PVE::Firewall::load_vmfw_conf($cluster_conf, 'ct', $param->{vmid});
432 my $ipset = $fw_conf->{ipset}->{$param->{name}};
433 die "no such IPSet '$param->{name}'\n" if !defined($ipset);
434
435 return ($cluster_conf, $fw_conf, $ipset);
436}
437
438sub save_config {
439 my ($class, $param, $fw_conf) = @_;
440
441 PVE::Firewall::save_vmfw_conf($param->{vmid}, $fw_conf);
442}
443
444__PACKAGE__->register_handlers();
445
c85c87f9
DM
446package PVE::API2::Firewall::BaseIPSetList;
447
448use strict;
449use warnings;
e74a87f5 450use PVE::JSONSchema qw(get_standard_option);
c85c87f9 451use PVE::Exception qw(raise_param_exc);
e74a87f5 452use PVE::Firewall;
c85c87f9
DM
453
454use base qw(PVE::RESTHandler);
455
1210ae94
DM
456sub load_config {
457 my ($class, $param) = @_;
458
459 die "implement this in subclass";
460
461 #return ($cluster_conf, $fw_conf);
462}
463
464sub save_config {
465 my ($class, $param, $fw_conf) = @_;
466
467 die "implement this in subclass";
468}
469
9f6845cf
DM
470sub rule_env {
471 my ($class, $param) = @_;
472
473 die "implement this in subclass";
474}
475
1210ae94
DM
476my $additional_param_hash_list = {};
477
478sub additional_parameters {
479 my ($class, $new_value) = @_;
480
481 if (defined($new_value)) {
482 $additional_param_hash_list->{$class} = $new_value;
483 }
484
485 # return a copy
486 my $copy = {};
487 my $org = $additional_param_hash_list->{$class} || {};
488 foreach my $p (keys %$org) { $copy->{$p} = $org->{$p}; }
489 return $copy;
490}
491
5d38d64f
DM
492my $get_ipset_list = sub {
493 my ($fw_conf) = @_;
494
495 my $res = [];
496 foreach my $name (keys %{$fw_conf->{ipset}}) {
497 my $data = {
498 name => $name,
499 };
500 if (my $comment = $fw_conf->{ipset_comments}->{$name}) {
501 $data->{comment} = $comment;
502 }
503 push @$res, $data;
504 }
505
506 my ($list, $digest) = PVE::Firewall::copy_list_with_digest($res);
507
508 return wantarray ? ($list, $digest) : $list;
509};
510
c85c87f9
DM
511sub register_index {
512 my ($class) = @_;
513
1210ae94
DM
514 my $properties = $class->additional_parameters();
515
c85c87f9
DM
516 $class->register_method({
517 name => 'ipset_index',
518 path => '',
519 method => 'GET',
520 description => "List IPSets",
9f6845cf 521 permissions => PVE::Firewall::rules_audit_permissions($class->rule_env()),
c85c87f9
DM
522 parameters => {
523 additionalProperties => 0,
1210ae94 524 properties => $properties,
c85c87f9
DM
525 },
526 returns => {
527 type => 'array',
528 items => {
529 type => "object",
530 properties => {
e74a87f5 531 name => get_standard_option('ipset-name'),
d72c631c
DM
532 digest => get_standard_option('pve-config-digest', { optional => 0} ),
533 comment => {
534 type => 'string',
535 optional => 1,
536 }
c85c87f9
DM
537 },
538 },
539 links => [ { rel => 'child', href => "{name}" } ],
540 },
541 code => sub {
542 my ($param) = @_;
543
1210ae94 544 my ($cluster_conf, $fw_conf) = $class->load_config($param);
c85c87f9 545
5d38d64f 546 return &$get_ipset_list($fw_conf);
c85c87f9
DM
547 }});
548}
549
550sub register_create {
551 my ($class) = @_;
552
1210ae94
DM
553 my $properties = $class->additional_parameters();
554
555 $properties->{name} = get_standard_option('ipset-name');
556
557 $properties->{comment} = { type => 'string', optional => 1 };
558
559 $properties->{digest} = get_standard_option('pve-config-digest');
560
561 $properties->{rename} = get_standard_option('ipset-name', {
562 description => "Rename an existing IPSet. You can set 'rename' to the same value as 'name' to update the 'comment' of an existing IPSet.",
563 optional => 1 });
564
c85c87f9
DM
565 $class->register_method({
566 name => 'create_ipset',
567 path => '',
568 method => 'POST',
569 description => "Create new IPSet",
570 protected => 1,
9f6845cf 571 permissions => PVE::Firewall::rules_modify_permissions($class->rule_env()),
c85c87f9
DM
572 parameters => {
573 additionalProperties => 0,
1210ae94 574 properties => $properties,
c85c87f9
DM
575 },
576 returns => { type => 'null' },
577 code => sub {
578 my ($param) = @_;
579
1210ae94 580 my ($cluster_conf, $fw_conf) = $class->load_config($param);
c85c87f9 581
bc374ca7 582 if ($param->{rename}) {
5d38d64f
DM
583 my (undef, $digest) = &$get_ipset_list($fw_conf);
584 PVE::Tools::assert_if_modified($digest, $param->{digest});
585
bc374ca7
DM
586 raise_param_exc({ name => "IPSet '$param->{rename}' does not exists" })
587 if !$fw_conf->{ipset}->{$param->{rename}};
5d38d64f 588
bc374ca7
DM
589 my $data = delete $fw_conf->{ipset}->{$param->{rename}};
590 $fw_conf->{ipset}->{$param->{name}} = $data;
d72c631c
DM
591 if (my $comment = delete $fw_conf->{ipset_comments}->{$param->{rename}}) {
592 $fw_conf->{ipset_comments}->{$param->{name}} = $comment;
593 }
594 $fw_conf->{ipset_comments}->{$param->{name}} = $param->{comment} if defined($param->{comment});
5d38d64f
DM
595 } else {
596 foreach my $name (keys %{$fw_conf->{ipset}}) {
597 raise_param_exc({ name => "IPSet '$name' already exists" })
598 if $name eq $param->{name};
599 }
600
bc374ca7 601 $fw_conf->{ipset}->{$param->{name}} = [];
d72c631c 602 $fw_conf->{ipset_comments}->{$param->{name}} = $param->{comment} if defined($param->{comment});
bc374ca7
DM
603 }
604
1210ae94 605 $class->save_config($param, $fw_conf);
c85c87f9
DM
606
607 return undef;
608 }});
609}
610
1210ae94 611sub register_handlers {
c85c87f9
DM
612 my ($class) = @_;
613
1210ae94
DM
614 $class->register_index();
615 $class->register_create();
616}
c85c87f9 617
1210ae94 618package PVE::API2::Firewall::ClusterIPSetList;
c85c87f9 619
1210ae94
DM
620use strict;
621use warnings;
622use PVE::Firewall;
5d38d64f 623
1210ae94
DM
624use base qw(PVE::API2::Firewall::BaseIPSetList);
625
9f6845cf
DM
626sub rule_env {
627 my ($class, $param) = @_;
628
629 return 'cluster';
630}
631
1210ae94
DM
632sub load_config {
633 my ($class, $param) = @_;
634
635 my $cluster_conf = PVE::Firewall::load_clusterfw_conf();
636 return (undef, $cluster_conf);
637}
c85c87f9 638
1210ae94
DM
639sub save_config {
640 my ($class, $param, $fw_conf) = @_;
c85c87f9 641
1210ae94
DM
642 PVE::Firewall::save_clusterfw_conf($fw_conf);
643}
c85c87f9 644
1210ae94
DM
645__PACKAGE__->register_handlers();
646
647__PACKAGE__->register_method ({
648 subclass => "PVE::API2::Firewall::ClusterIPset",
649 path => '{name}',
650 # set fragment delimiter (no subdirs) - we need that, because CIDR address contain a slash '/'
651 fragmentDelimiter => '',
652});
653
654package PVE::API2::Firewall::VMIPSetList;
655
656use strict;
657use warnings;
658use PVE::JSONSchema qw(get_standard_option);
659use PVE::Firewall;
660
661use base qw(PVE::API2::Firewall::BaseIPSetList);
662
663__PACKAGE__->additional_parameters({
664 node => get_standard_option('pve-node'),
665 vmid => get_standard_option('pve-vmid'),
666});
667
9f6845cf
DM
668sub rule_env {
669 my ($class, $param) = @_;
670
671 return 'vm';
672}
673
1210ae94
DM
674sub load_config {
675 my ($class, $param) = @_;
676
677 my $cluster_conf = PVE::Firewall::load_clusterfw_conf();
678 my $fw_conf = PVE::Firewall::load_vmfw_conf($cluster_conf, 'vm', $param->{vmid});
679 return ($cluster_conf, $fw_conf);
c85c87f9
DM
680}
681
1210ae94
DM
682sub save_config {
683 my ($class, $param, $fw_conf) = @_;
c85c87f9 684
1210ae94 685 PVE::Firewall::save_vmfw_conf($param->{vmid}, $fw_conf);
c85c87f9
DM
686}
687
1210ae94
DM
688__PACKAGE__->register_handlers();
689
690__PACKAGE__->register_method ({
691 subclass => "PVE::API2::Firewall::VMIPset",
692 path => '{name}',
693 # set fragment delimiter (no subdirs) - we need that, because CIDR address contain a slash '/'
694 fragmentDelimiter => '',
695});
696
697package PVE::API2::Firewall::CTIPSetList;
c85c87f9
DM
698
699use strict;
700use warnings;
1210ae94 701use PVE::JSONSchema qw(get_standard_option);
c85c87f9
DM
702use PVE::Firewall;
703
704use base qw(PVE::API2::Firewall::BaseIPSetList);
705
1210ae94
DM
706__PACKAGE__->additional_parameters({
707 node => get_standard_option('pve-node'),
708 vmid => get_standard_option('pve-vmid'),
709});
710
9f6845cf
DM
711sub rule_env {
712 my ($class, $param) = @_;
713
714 return 'ct';
715}
716
c85c87f9 717sub load_config {
1210ae94 718 my ($class, $param) = @_;
c85c87f9 719
1210ae94
DM
720 my $cluster_conf = PVE::Firewall::load_clusterfw_conf();
721 my $fw_conf = PVE::Firewall::load_vmfw_conf($cluster_conf, 'ct', $param->{vmid});
722 return ($cluster_conf, $fw_conf);
c85c87f9
DM
723}
724
725sub save_config {
1210ae94 726 my ($class, $param, $fw_conf) = @_;
c85c87f9 727
1210ae94 728 PVE::Firewall::save_vmfw_conf($param->{vmid}, $fw_conf);
c85c87f9
DM
729}
730
731__PACKAGE__->register_handlers();
732
733__PACKAGE__->register_method ({
1210ae94 734 subclass => "PVE::API2::Firewall::CTIPset",
c85c87f9
DM
735 path => '{name}',
736 # set fragment delimiter (no subdirs) - we need that, because CIDR address contain a slash '/'
737 fragmentDelimiter => '',
738});
739
009ee3ac 7401;